From 8a39ee361feb9bf46d728ff1ba4f07ca1d9610b1 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Thu, 19 Jun 2014 09:22:53 +0200 Subject: Imported Upstream version 1.3 --- AUTHORS | 73 +- CONTRIBUTORS | 90 +- VERSION | 2 +- api/except.txt | 313 + api/go1.3.txt | 2053 +++ api/next.txt | 117 + doc/Makefile | 32 - doc/articles/race_detector.html | 388 + doc/articles/wiki/Makefile | 10 - doc/articles/wiki/final.go | 23 + doc/articles/wiki/index.html | 2 +- doc/articles/wiki/test.bash | 26 +- doc/asm.html | 11 +- doc/codewalk/sharemem.xml | 2 +- doc/contrib.html | 42 +- doc/contribute.html | 92 +- doc/debugging_with_gdb.html | 21 +- doc/devel/release.html | 36 +- doc/docs.html | 7 +- doc/effective_go.html | 99 +- doc/gccgo_install.html | 4 +- doc/go1.3.html | 599 + doc/go1.html | 2 +- doc/go_faq.html | 39 +- doc/go_mem.html | 37 +- doc/go_spec.html | 511 +- doc/gopher/README | 3 + doc/help.html | 2 +- doc/install-source.html | 25 +- doc/install.html | 33 +- doc/root.html | 1 - include/bio.h | 4 +- include/bootexec.h | 169 - include/link.h | 616 + include/mach.h | 411 - include/plan9/386/u.h | 2 + include/plan9/amd64/u.h | 2 + include/plan9/bio.h | 8 + include/plan9/errno.h | 7 + include/plan9/fmt.h | 64 + include/plan9/libc.h | 7 +- include/plan9/link.h | 5 + include/plan9/mach.h | 5 - include/plan9/mklibc.rc | 8 + include/plan9/stdarg.h | 3 + include/plan9/ureg_amd64.h | 5 - include/plan9/ureg_arm.h | 5 - include/plan9/ureg_x86.h | 5 - include/plan9/utf.h | 5 + include/u.h | 2 + include/ureg_amd64.h | 58 - include/ureg_arm.h | 49 - include/ureg_x86.h | 53 - lib/time/update.bash | 6 +- lib/time/zoneinfo.zip | Bin 374754 -> 358933 bytes misc/bash/go | 17 +- misc/benchcmp | 127 +- misc/cgo/errors/err3.go | 18 + misc/cgo/errors/test.bash | 1 + misc/cgo/nocgo/nocgo.go | 22 + misc/cgo/nocgo/nocgo_test.go | 14 + misc/cgo/test/backdoor/backdoor.go | 1 + misc/cgo/test/backdoor/backdoor_gccgo.go | 11 + misc/cgo/test/backdoor/runtime.c | 7 + misc/cgo/test/cgo_linux_test.go | 1 + misc/cgo/test/cgo_test.go | 3 + misc/cgo/test/issue6833.go | 27 + misc/cgo/test/issue6833_c.c | 10 + misc/cgo/test/issue6997_linux.c | 26 + misc/cgo/test/issue6997_linux.go | 40 + misc/cgo/test/issue7234_test.go | 21 + misc/cgo/test/issue7560.go | 44 + misc/cgo/test/issue7665.go | 25 + misc/cgo/test/issue7695_test.go | 27 + misc/cgo/test/issue7786.go | 51 + misc/cgo/test/issue8148.go | 31 + misc/cgo/test/issue8331.h | 7 + misc/cgo/test/issue8331a.go | 15 + misc/cgo/test/issue8331b.go | 13 + misc/cgo/testcdefs/test.bash | 2 +- misc/cgo/testso/cgoso_c.c | 5 + misc/cgo/testso/cgoso_unix.go | 20 + misc/cgo/testtls/tls.go | 14 +- misc/dist/bindist.go | 1041 -- misc/dist/darwin/Distribution | 32 - misc/dist/darwin/Resources/bg.png | Bin 11466 -> 0 bytes misc/dist/darwin/etc/paths.d/go | 1 - misc/dist/darwin/scripts/postinstall | 10 - misc/dist/darwin/scripts/preinstall | 8 - misc/dist/windows/LICENSE.rtf | Bin 1687 -> 0 bytes misc/dist/windows/README.txt | 25 - misc/dist/windows/images/Banner.jpg | Bin 6643 -> 0 bytes misc/dist/windows/images/Dialog.jpg | Bin 16428 -> 0 bytes misc/dist/windows/images/DialogLeft.jpg | Bin 12961 -> 0 bytes misc/dist/windows/images/gopher.ico | Bin 30166 -> 0 bytes misc/dist/windows/installer.wxs | 164 - misc/emacs/go-mode.el | 63 +- misc/goplay/Makefile | 6 - misc/goplay/README | 1 - misc/goplay/doc.go | 23 - misc/goplay/goplay.go | 288 - misc/makerelease/darwin/Distribution | 32 + misc/makerelease/darwin/Resources/bg.png | Bin 0 -> 11466 bytes misc/makerelease/darwin/etc/paths.d/go | 1 + misc/makerelease/darwin/scripts/postinstall | 10 + misc/makerelease/darwin/scripts/preinstall | 8 + misc/makerelease/makerelease.go | 1030 ++ misc/makerelease/windows/LICENSE.rtf | Bin 0 -> 1687 bytes misc/makerelease/windows/README.txt | 25 + misc/makerelease/windows/images/Banner.jpg | Bin 0 -> 6643 bytes misc/makerelease/windows/images/Dialog.jpg | Bin 0 -> 16428 bytes misc/makerelease/windows/images/DialogLeft.jpg | Bin 0 -> 12961 bytes misc/makerelease/windows/images/gopher.ico | Bin 0 -> 30166 bytes misc/makerelease/windows/installer.wxs | 164 + misc/nacl/README | 63 + misc/nacl/go_nacl_386_exec | 10 + misc/nacl/go_nacl_amd64p32_exec | 10 + misc/nacl/mkzip.go | 220 + misc/nacl/testdata/bin/placeholder | 0 misc/nacl/testdata/empty | 0 misc/nacl/testdata/group | 8 + misc/nacl/testdata/hosts | 1 + misc/nacl/testdata/mime.types | 1596 +++ misc/nacl/testzip.proto | 113 + misc/notepadplus/functionList.xml | 7 + misc/pprof | 9 + misc/vim/autoload/go/complete.vim | 2 +- misc/vim/ftplugin/go.vim | 4 +- misc/vim/ftplugin/go/fmt.vim | 2 +- misc/vim/indent/go.vim | 20 +- misc/vim/readme.txt | 8 +- misc/zsh/go | 5 +- src/all.bash | 2 +- src/cmd/5a/a.h | 48 +- src/cmd/5a/a.y | 30 +- src/cmd/5a/lex.c | 377 +- src/cmd/5a/y.tab.c | 981 +- src/cmd/5a/y.tab.h | 38 +- src/cmd/5c/gc.h | 83 +- src/cmd/5c/list.c | 303 +- src/cmd/5c/peep.c | 44 +- src/cmd/5c/reg.c | 20 +- src/cmd/5c/swt.c | 285 +- src/cmd/5c/txt.c | 44 +- src/cmd/5g/cgen.c | 66 +- src/cmd/5g/galign.c | 9 +- src/cmd/5g/gg.h | 50 - src/cmd/5g/ggen.c | 195 +- src/cmd/5g/gobj.c | 264 +- src/cmd/5g/gsubr.c | 66 +- src/cmd/5g/list.c | 342 - src/cmd/5g/opt.h | 1 + src/cmd/5g/peep.c | 156 +- src/cmd/5g/prog.c | 10 +- src/cmd/5g/reg.c | 267 +- src/cmd/5l/5.out.h | 85 +- src/cmd/5l/asm.c | 1542 +-- src/cmd/5l/l.h | 349 +- src/cmd/5l/list.c | 427 +- src/cmd/5l/noop.c | 671 +- src/cmd/5l/obj.c | 731 +- src/cmd/5l/optab.c | 277 - src/cmd/5l/pass.c | 409 - src/cmd/5l/prof.c | 211 - src/cmd/5l/softfloat.c | 91 - src/cmd/5l/span.c | 937 -- src/cmd/6a/a.h | 54 +- src/cmd/6a/a.y | 28 +- src/cmd/6a/lex.c | 382 +- src/cmd/6a/y.tab.c | 1457 +- src/cmd/6a/y.tab.h | 50 +- src/cmd/6c/gc.h | 75 +- src/cmd/6c/list.c | 355 +- src/cmd/6c/peep.c | 16 +- src/cmd/6c/reg.c | 31 +- src/cmd/6c/sgen.c | 2 +- src/cmd/6c/swt.c | 297 +- src/cmd/6c/txt.c | 75 +- src/cmd/6g/cgen.c | 100 +- src/cmd/6g/galign.c | 28 +- src/cmd/6g/gg.h | 49 +- src/cmd/6g/ggen.c | 236 +- src/cmd/6g/gobj.c | 260 +- src/cmd/6g/gsubr.c | 104 +- src/cmd/6g/list.c | 364 - src/cmd/6g/opt.h | 1 + src/cmd/6g/peep.c | 26 +- src/cmd/6g/prog.c | 7 +- src/cmd/6g/reg.c | 253 +- src/cmd/6l/6.out.h | 44 +- src/cmd/6l/asm.c | 299 +- src/cmd/6l/l.h | 374 +- src/cmd/6l/list.c | 396 +- src/cmd/6l/obj.c | 701 +- src/cmd/6l/optab.c | 1369 -- src/cmd/6l/pass.c | 991 -- src/cmd/6l/prof.c | 171 - src/cmd/6l/span.c | 1846 --- src/cmd/8a/a.h | 55 +- src/cmd/8a/a.y | 26 +- src/cmd/8a/lex.c | 380 +- src/cmd/8a/y.tab.c | 1446 +- src/cmd/8a/y.tab.h | 50 +- src/cmd/8c/gc.h | 75 +- src/cmd/8c/list.c | 316 +- src/cmd/8c/peep.c | 16 +- src/cmd/8c/reg.c | 29 +- src/cmd/8c/swt.c | 273 +- src/cmd/8c/txt.c | 49 +- src/cmd/8g/cgen.c | 43 +- src/cmd/8g/galign.c | 9 +- src/cmd/8g/gg.h | 47 +- src/cmd/8g/ggen.c | 175 +- src/cmd/8g/gobj.c | 259 +- src/cmd/8g/gsubr.c | 69 +- src/cmd/8g/list.c | 316 - src/cmd/8g/opt.h | 3 +- src/cmd/8g/peep.c | 24 +- src/cmd/8g/prog.c | 21 +- src/cmd/8g/reg.c | 261 +- src/cmd/8l/8.out.h | 50 +- src/cmd/8l/asm.c | 393 +- src/cmd/8l/l.h | 330 +- src/cmd/8l/list.c | 313 +- src/cmd/8l/obj.c | 698 +- src/cmd/8l/optab.c | 1030 -- src/cmd/8l/pass.c | 858 -- src/cmd/8l/prof.c | 173 - src/cmd/8l/span.c | 1507 -- src/cmd/addr2line/addr2line_test.go | 115 + src/cmd/addr2line/main.c | 90 - src/cmd/addr2line/main.go | 253 + src/cmd/api/goapi.go | 2 +- src/cmd/api/run.go | 4 +- src/cmd/cc/cc.h | 38 +- src/cmd/cc/lex.c | 127 +- src/cmd/cc/lexbody | 76 +- src/cmd/cc/macbody | 56 +- src/cmd/cc/pgen.c | 133 +- src/cmd/cc/pswt.c | 29 - src/cmd/cc/sub.c | 10 + src/cmd/cgo/doc.go | 28 + src/cmd/cgo/gcc.go | 84 +- src/cmd/cgo/out.go | 47 +- src/cmd/dist/a.h | 5 +- src/cmd/dist/arm.c | 12 +- src/cmd/dist/build.c | 267 +- src/cmd/dist/buildgc.c | 10 +- src/cmd/dist/buildgo.c | 2 +- src/cmd/dist/buildruntime.c | 98 +- src/cmd/dist/goc2c.c | 116 +- src/cmd/dist/unix.c | 9 + src/cmd/dist/windows.c | 22 +- src/cmd/gc/align.c | 10 +- src/cmd/gc/array.c | 129 + src/cmd/gc/bits.c | 2 +- src/cmd/gc/builtin.c | 30 +- src/cmd/gc/bv.c | 134 +- src/cmd/gc/closure.c | 20 + src/cmd/gc/const.c | 92 +- src/cmd/gc/dcl.c | 28 +- src/cmd/gc/doc.go | 6 +- src/cmd/gc/esc.c | 190 +- src/cmd/gc/export.c | 5 +- src/cmd/gc/fmt.c | 115 +- src/cmd/gc/gen.c | 95 +- src/cmd/gc/go.h | 126 +- src/cmd/gc/go.y | 6 + src/cmd/gc/inl.c | 3 + src/cmd/gc/lex.c | 97 +- src/cmd/gc/md5.c | 4 +- src/cmd/gc/md5.h | 2 +- src/cmd/gc/mparith1.c | 44 +- src/cmd/gc/mparith2.c | 10 +- src/cmd/gc/mparith3.c | 115 +- src/cmd/gc/obj.c | 281 +- src/cmd/gc/order.c | 930 +- src/cmd/gc/pgen.c | 398 +- src/cmd/gc/plive.c | 1985 +++ src/cmd/gc/popt.c | 79 +- src/cmd/gc/racewalk.c | 3 +- src/cmd/gc/range.c | 77 +- src/cmd/gc/reflect.c | 149 +- src/cmd/gc/runtime.go | 31 +- src/cmd/gc/select.c | 116 +- src/cmd/gc/sinit.c | 98 +- src/cmd/gc/subr.c | 63 +- src/cmd/gc/swt.c | 2 +- src/cmd/gc/typecheck.c | 255 +- src/cmd/gc/walk.c | 453 +- src/cmd/gc/y.tab.c | 1762 +-- src/cmd/gc/y.tab.h | 46 +- src/cmd/go/build.go | 626 +- src/cmd/go/clean.go | 41 +- src/cmd/go/context.go | 36 + src/cmd/go/discovery.go | 3 + src/cmd/go/doc.go | 116 +- src/cmd/go/env.go | 34 +- src/cmd/go/get.go | 11 +- src/cmd/go/help.go | 46 +- src/cmd/go/list.go | 55 +- src/cmd/go/main.go | 6 + src/cmd/go/pkg.go | 33 +- src/cmd/go/pkg_test.go | 73 + src/cmd/go/run.go | 39 +- src/cmd/go/signal_unix.go | 2 +- src/cmd/go/test.bash | 211 +- src/cmd/go/test.go | 142 +- src/cmd/go/testdata/cgocover/p.go | 19 + src/cmd/go/testdata/cgocover/p_test.go | 7 + src/cmd/go/testdata/dep_test.go | 7 + src/cmd/go/testdata/src/notest/hello.go | 6 + src/cmd/go/testdata/src/testcycle/p1/p1.go | 7 + src/cmd/go/testdata/src/testcycle/p1/p1_test.go | 6 + src/cmd/go/testdata/src/testcycle/p2/p2.go | 7 + src/cmd/go/testdata/src/testcycle/p3/p3.go | 5 + src/cmd/go/testdata/src/testcycle/p3/p3_test.go | 10 + src/cmd/go/testdata/src/xtestonly/f.go | 3 + src/cmd/go/testdata/src/xtestonly/f_test.go | 12 + src/cmd/go/testdata/standalone_test.go | 6 + src/cmd/go/testdata/testonly/p_test.go | 1 + src/cmd/go/testflag.go | 23 +- src/cmd/go/vcs.go | 10 +- src/cmd/gofmt/doc.go | 11 +- src/cmd/gofmt/gofmt.go | 39 +- src/cmd/gofmt/gofmt_test.go | 1 - src/cmd/gofmt/long_test.go | 2 +- src/cmd/gofmt/rewrite.go | 27 +- src/cmd/gofmt/testdata/typeswitch.golden | 2 +- src/cmd/gofmt/testdata/typeswitch.input | 2 +- src/cmd/ld/data.c | 714 +- src/cmd/ld/decodesym.c | 109 +- src/cmd/ld/doc.go | 4 + src/cmd/ld/dwarf.c | 602 +- src/cmd/ld/dwarf.h | 8 +- src/cmd/ld/elf.c | 277 +- src/cmd/ld/elf.h | 15 +- src/cmd/ld/go.c | 157 +- src/cmd/ld/ldelf.c | 64 +- src/cmd/ld/ldmacho.c | 56 +- src/cmd/ld/ldpe.c | 60 +- src/cmd/ld/lib.c | 1625 +-- src/cmd/ld/lib.h | 388 +- src/cmd/ld/macho.c | 123 +- src/cmd/ld/pass.c | 104 + src/cmd/ld/pcln.c | 244 + src/cmd/ld/pe.c | 212 +- src/cmd/ld/pe.h | 2 +- src/cmd/ld/pobj.c | 197 + src/cmd/ld/symtab.c | 244 +- src/cmd/ld/textflag.h | 2 + src/cmd/nm/Makefile | 5 - src/cmd/nm/debug_goobj.go | 670 + src/cmd/nm/doc.go | 56 +- src/cmd/nm/elf.go | 57 + src/cmd/nm/goobj.go | 67 + src/cmd/nm/macho.go | 69 + src/cmd/nm/nm.c | 401 - src/cmd/nm/nm.go | 184 + src/cmd/nm/nm_test.go | 99 + src/cmd/nm/pe.go | 98 + src/cmd/nm/plan9obj.go | 48 + src/cmd/objdump/Makefile | 10 + src/cmd/objdump/armasm.go | 10821 +++++++++++++++ src/cmd/objdump/elf.go | 65 + src/cmd/objdump/macho.go | 77 + src/cmd/objdump/main.c | 68 - src/cmd/objdump/main.go | 519 + src/cmd/objdump/objdump_test.go | 193 + src/cmd/objdump/pe.go | 99 + src/cmd/objdump/plan9obj.go | 63 + src/cmd/objdump/testdata/fmthello.go | 7 + src/cmd/objdump/x86.go | 13800 +++++++++++++++++++ src/cmd/pack/Makefile | 5 - src/cmd/pack/ar.c | 1727 --- src/cmd/pack/doc.go | 40 +- src/cmd/pack/pack.go | 486 + src/cmd/pack/pack_test.go | 402 + src/cmd/yacc/Makefile | 8 +- src/cmd/yacc/expr.y | 2 +- src/cmd/yacc/yacc.go | 15 + src/lib9/_exits.c | 2 + src/lib9/_p9dir.c | 2 + src/lib9/atoi.c | 2 + src/lib9/await.c | 1 + src/lib9/cleanname.c | 2 + src/lib9/create.c | 2 + src/lib9/ctime.c | 2 + src/lib9/dirfstat.c | 2 + src/lib9/dirfwstat.c | 2 + src/lib9/dirstat.c | 2 + src/lib9/dirwstat.c | 2 + src/lib9/dup.c | 2 + src/lib9/errstr.c | 3 +- src/lib9/exec.c | 2 + src/lib9/execl.c | 2 + src/lib9/exitcode.c | 2 + src/lib9/exits.c | 2 + src/lib9/fmt/dorfmt.c | 1 - src/lib9/fmt/errfmt.c | 32 + src/lib9/fmt/fltfmt.c | 6 +- src/lib9/fmt/fmtfd.c | 2 +- src/lib9/fmtlock2.c | 2 + src/lib9/getenv.c | 2 + src/lib9/getwd.c | 2 + src/lib9/jmp.c | 1 + src/lib9/main.c | 4 +- src/lib9/nan.c | 2 + src/lib9/notify.c | 1 + src/lib9/nulldir.c | 2 + src/lib9/open.c | 2 + src/lib9/readn.c | 2 + src/lib9/rfork.c | 1 + src/lib9/run_plan9.c | 2 + src/lib9/run_unix.c | 2 +- src/lib9/seek.c | 2 + src/lib9/strecpy.c | 2 + src/lib9/sysfatal.c | 2 + src/lib9/tempdir_plan9.c | 2 + src/lib9/tempdir_unix.c | 2 +- src/lib9/time.c | 2 + src/lib9/tokenize.c | 2 + src/lib9/utf/Makefile | 4 +- src/lib9/utf/runetype.c | 2 +- src/lib9/utf/runetypebody-6.2.0.h | 1639 --- src/lib9/utf/runetypebody-6.3.0.h | 1638 +++ src/lib9/utf/utfdef.h | 1 - src/lib9/utf/utfecpy.c | 4 +- src/lib9/utf/utflen.c | 1 - src/lib9/utf/utfrrune.c | 4 +- src/lib9/utf/utfrune.c | 4 +- src/lib9/utf/utfutf.c | 3 +- src/libbio/bgetc.c | 2 +- src/libbio/bgetrune.c | 1 - src/libbio/bputrune.c | 4 +- src/libbio/bseek.c | 2 +- src/liblink/Makefile | 5 + src/liblink/asm5.c | 2458 ++++ src/liblink/asm6.c | 3585 +++++ src/liblink/asm8.c | 2785 ++++ src/liblink/data.c | 370 + src/liblink/go.c | 74 + src/liblink/ld.c | 258 + src/liblink/list5.c | 356 + src/liblink/list6.c | 406 + src/liblink/list8.c | 354 + src/liblink/obj.c | 296 + src/liblink/obj5.c | 1068 ++ src/liblink/obj6.c | 1171 ++ src/liblink/obj8.c | 859 ++ src/liblink/objfile.c | 746 + src/liblink/pass.c | 115 + src/liblink/pcln.c | 365 + src/liblink/sym.c | 271 + src/libmach/5.c | 92 - src/libmach/5db.c | 1095 -- src/libmach/5obj.c | 171 - src/libmach/6.c | 145 - src/libmach/6obj.c | 173 - src/libmach/8.c | 108 - src/libmach/8db.c | 2447 ---- src/libmach/8obj.c | 170 - src/libmach/Makefile | 5 - src/libmach/access.c | 241 - src/libmach/darwin.c | 897 -- src/libmach/dragonfly.c | 62 - src/libmach/elf.h | 182 - src/libmach/executable.c | 1525 -- src/libmach/fakeobj.c | 29 - src/libmach/freebsd.c | 62 - src/libmach/linux.c | 1014 -- src/libmach/machdata.c | 477 - src/libmach/macho.h | 100 - src/libmach/map.c | 183 - src/libmach/netbsd.c | 56 - src/libmach/obj.c | 393 - src/libmach/obj.h | 53 - src/libmach/openbsd.c | 56 - src/libmach/plan9.c | 72 - src/libmach/setmach.c | 203 - src/libmach/swap.c | 107 - src/libmach/sym.c | 1883 --- src/libmach/windows.c | 87 - src/make.bash | 22 +- src/make.rc | 3 + src/nacltest.bash | 56 + src/pkg/archive/tar/common.go | 3 + src/pkg/archive/tar/reader.go | 465 +- src/pkg/archive/tar/reader_test.go | 368 +- src/pkg/archive/tar/stat_atim.go | 2 +- src/pkg/archive/tar/stat_unix.go | 2 +- src/pkg/archive/tar/tar_test.go | 4 + src/pkg/archive/tar/testdata/sparse-formats.tar | Bin 0 -> 17920 bytes src/pkg/archive/tar/testdata/writer-big-long.tar | Bin 0 -> 4096 bytes src/pkg/archive/tar/testdata/xattrs.tar | Bin 0 -> 5120 bytes src/pkg/archive/tar/writer.go | 10 +- src/pkg/archive/tar/writer_test.go | 63 + src/pkg/archive/zip/reader.go | 2 +- src/pkg/archive/zip/reader_test.go | 28 +- src/pkg/archive/zip/register.go | 41 +- src/pkg/archive/zip/struct.go | 4 +- src/pkg/archive/zip/testdata/zip64-2.zip | Bin 0 -> 266 bytes src/pkg/archive/zip/writer_test.go | 18 + src/pkg/bufio/bufio.go | 147 +- src/pkg/bufio/bufio_test.go | 343 +- src/pkg/bufio/scan.go | 6 +- src/pkg/bufio/scan_test.go | 14 +- src/pkg/bytes/bytes.go | 10 +- src/pkg/bytes/bytes_test.go | 36 +- src/pkg/bytes/compare_test.go | 4 + src/pkg/bytes/reader.go | 52 +- src/pkg/bytes/reader_test.go | 82 +- src/pkg/compress/bzip2/bzip2_test.go | 12 +- src/pkg/compress/bzip2/huffman.go | 32 +- src/pkg/compress/flate/fixedhuff.go | 4 + src/pkg/compress/flate/flate_test.go | 2 +- src/pkg/compress/flate/inflate.go | 4 +- src/pkg/compress/flate/reader_test.go | 2 +- src/pkg/compress/gzip/gunzip.go | 15 + src/pkg/compress/gzip/gunzip_test.go | 36 +- src/pkg/compress/gzip/gzip.go | 8 +- src/pkg/compress/gzip/gzip_test.go | 2 +- src/pkg/compress/lzw/reader.go | 4 +- src/pkg/compress/lzw/reader_test.go | 4 +- src/pkg/compress/lzw/writer.go | 4 +- src/pkg/compress/zlib/example_test.go | 2 +- src/pkg/compress/zlib/reader.go | 3 +- src/pkg/compress/zlib/reader_test.go | 2 +- src/pkg/compress/zlib/writer.go | 4 +- src/pkg/compress/zlib/writer_test.go | 2 +- src/pkg/container/heap/example_pq_test.go | 22 +- src/pkg/container/heap/heap.go | 4 +- src/pkg/container/list/example_test.go | 2 +- src/pkg/container/list/list.go | 10 +- src/pkg/container/list/list_test.go | 56 + src/pkg/container/ring/ring_test.go | 8 + src/pkg/crypto/aes/aes_test.go | 28 + src/pkg/crypto/aes/cipher.go | 12 + src/pkg/crypto/aes/cipher_asm.go | 2 + src/pkg/crypto/cipher/benchmark_test.go | 139 + src/pkg/crypto/cipher/cbc.go | 55 +- src/pkg/crypto/cipher/cbc_aes_test.go | 46 +- src/pkg/crypto/cipher/cfb.go | 60 +- src/pkg/crypto/cipher/cfb_test.go | 8 +- src/pkg/crypto/cipher/cipher.go | 10 - src/pkg/crypto/cipher/ctr.go | 55 +- src/pkg/crypto/cipher/gcm.go | 27 +- src/pkg/crypto/cipher/gcm_test.go | 16 - src/pkg/crypto/cipher/ofb.go | 42 +- src/pkg/crypto/cipher/xor.go | 84 + src/pkg/crypto/cipher/xor_test.go | 28 + src/pkg/crypto/dsa/dsa.go | 12 +- src/pkg/crypto/ecdsa/ecdsa.go | 12 +- src/pkg/crypto/hmac/hmac_test.go | 66 +- src/pkg/crypto/md5/example_test.go | 6 + src/pkg/crypto/md5/gen.go | 9 +- src/pkg/crypto/md5/md5_test.go | 13 + src/pkg/crypto/md5/md5block.go | 8 +- src/pkg/crypto/md5/md5block_amd64p32.s | 184 + src/pkg/crypto/md5/md5block_decl.go | 2 +- src/pkg/crypto/md5/md5block_generic.go | 9 + src/pkg/crypto/rand/rand_unix.go | 2 +- src/pkg/crypto/rand/util.go | 8 +- src/pkg/crypto/rand/util_test.go | 65 + src/pkg/crypto/rc4/rc4.go | 17 + src/pkg/crypto/rc4/rc4_amd64p32.s | 192 + src/pkg/crypto/rc4/rc4_asm.go | 2 +- src/pkg/crypto/rc4/rc4_ref.go | 11 +- src/pkg/crypto/rc4/rc4_test.go | 19 +- src/pkg/crypto/rsa/pkcs1v15.go | 12 +- src/pkg/crypto/rsa/pkcs1v15_test.go | 22 + src/pkg/crypto/rsa/pss.go | 6 +- src/pkg/crypto/rsa/rsa.go | 14 +- src/pkg/crypto/rsa/rsa_test.go | 2 +- src/pkg/crypto/sha1/example_test.go | 9 +- src/pkg/crypto/sha1/sha1.go | 10 +- src/pkg/crypto/sha1/sha1_test.go | 27 + src/pkg/crypto/sha1/sha1block.go | 10 +- src/pkg/crypto/sha1/sha1block_386.s | 10 +- src/pkg/crypto/sha1/sha1block_amd64.s | 10 +- src/pkg/crypto/sha1/sha1block_amd64p32.s | 216 + src/pkg/crypto/sha1/sha1block_arm.s | 217 + src/pkg/crypto/sha1/sha1block_decl.go | 2 +- src/pkg/crypto/sha1/sha1block_generic.go | 9 + src/pkg/crypto/sha256/sha256.go | 12 +- src/pkg/crypto/sha256/sha256_test.go | 18 + src/pkg/crypto/sha256/sha256block.go | 2 + src/pkg/crypto/sha256/sha256block_386.s | 283 + src/pkg/crypto/sha256/sha256block_amd64.s | 256 + src/pkg/crypto/sha256/sha256block_decl.go | 11 + src/pkg/crypto/sha512/sha512.go | 10 +- src/pkg/crypto/sha512/sha512_test.go | 18 + src/pkg/crypto/sha512/sha512block.go | 2 + src/pkg/crypto/sha512/sha512block_amd64.s | 273 + src/pkg/crypto/sha512/sha512block_decl.go | 11 + src/pkg/crypto/subtle/constant_time.go | 4 + src/pkg/crypto/tls/common.go | 153 +- src/pkg/crypto/tls/conn.go | 169 +- src/pkg/crypto/tls/example_test.go | 57 + src/pkg/crypto/tls/generate_cert.go | 13 +- src/pkg/crypto/tls/handshake_client.go | 362 +- src/pkg/crypto/tls/handshake_client_test.go | 3351 +---- src/pkg/crypto/tls/handshake_messages.go | 115 +- src/pkg/crypto/tls/handshake_messages_test.go | 4 +- src/pkg/crypto/tls/handshake_server.go | 60 +- src/pkg/crypto/tls/handshake_server_test.go | 3838 +----- src/pkg/crypto/tls/handshake_test.go | 167 + src/pkg/crypto/tls/key_agreement.go | 79 +- .../testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA | 129 + .../testdata/Client-TLSv10-ClientCert-ECDSA-RSA | 125 + .../testdata/Client-TLSv10-ClientCert-RSA-ECDSA | 128 + .../tls/testdata/Client-TLSv10-ClientCert-RSA-RSA | 124 + .../tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES | 87 + .../tls/testdata/Client-TLSv10-ECDHE-RSA-AES | 97 + src/pkg/crypto/tls/testdata/Client-TLSv10-RSA-RC4 | 83 + .../tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES | 89 + .../tls/testdata/Client-TLSv11-ECDHE-RSA-AES | 99 + src/pkg/crypto/tls/testdata/Client-TLSv11-RSA-RC4 | 83 + .../testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA | 134 + .../testdata/Client-TLSv12-ClientCert-ECDSA-RSA | 127 + .../testdata/Client-TLSv12-ClientCert-RSA-ECDSA | 133 + .../tls/testdata/Client-TLSv12-ClientCert-RSA-RSA | 126 + .../tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES | 89 + .../tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM | 84 + .../tls/testdata/Client-TLSv12-ECDHE-RSA-AES | 99 + src/pkg/crypto/tls/testdata/Client-TLSv12-RSA-RC4 | 83 + src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-3DES | 83 + src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-AES | 84 + src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-RC4 | 79 + .../tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES | 84 + src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-3DES | 79 + src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-AES | 82 + src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-RC4 | 76 + src/pkg/crypto/tls/testdata/Server-TLSv11-RSA-RC4 | 76 + .../Server-TLSv12-CipherSuiteCertPreferenceECDSA | 91 + .../Server-TLSv12-CipherSuiteCertPreferenceRSA | 101 + .../Server-TLSv12-ClientAuthRequestedAndECDSAGiven | 122 + .../Server-TLSv12-ClientAuthRequestedAndGiven | 121 + .../Server-TLSv12-ClientAuthRequestedNotGiven | 81 + .../tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES | 89 + .../crypto/tls/testdata/Server-TLSv12-IssueTicket | 87 + src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-3DES | 83 + src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-AES | 87 + .../crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM | 93 + src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-RC4 | 79 + src/pkg/crypto/tls/testdata/Server-TLSv12-Resume | 36 + src/pkg/crypto/tls/testdata/Server-TLSv12-SNI | 76 + src/pkg/crypto/tls/tls.go | 86 +- src/pkg/crypto/tls/tls_test.go | 130 + src/pkg/crypto/x509/example_test.go | 91 + src/pkg/crypto/x509/pkix/pkix.go | 7 + src/pkg/crypto/x509/root_cgo_darwin.go | 79 + src/pkg/crypto/x509/root_darwin.go | 78 +- src/pkg/crypto/x509/root_darwin_test.go | 50 + src/pkg/crypto/x509/root_nocgo_darwin.go | 11 + src/pkg/crypto/x509/root_stub.go | 14 - src/pkg/crypto/x509/root_unix.go | 2 +- src/pkg/crypto/x509/verify.go | 3 +- src/pkg/crypto/x509/verify_test.go | 367 +- src/pkg/crypto/x509/x509.go | 602 +- src/pkg/crypto/x509/x509_test.go | 241 +- src/pkg/crypto/x509/x509_test_import.go | 53 + src/pkg/database/sql/convert.go | 50 +- src/pkg/database/sql/convert_test.go | 56 + src/pkg/database/sql/driver/driver.go | 2 +- src/pkg/database/sql/example_test.go | 1 + src/pkg/database/sql/fakedb_test.go | 32 +- src/pkg/database/sql/sql.go | 166 +- src/pkg/database/sql/sql_test.go | 137 +- src/pkg/debug/dwarf/const.go | 35 +- src/pkg/debug/dwarf/entry.go | 16 +- src/pkg/debug/dwarf/open.go | 11 +- src/pkg/debug/dwarf/testdata/typedef.elf4 | Bin 0 -> 9496 bytes src/pkg/debug/dwarf/type.go | 75 +- src/pkg/debug/dwarf/type_test.go | 2 + src/pkg/debug/dwarf/typeunit.go | 166 + src/pkg/debug/dwarf/unit.go | 2 +- src/pkg/debug/elf/elf.go | 2 +- src/pkg/debug/elf/elf_test.go | 2 +- src/pkg/debug/elf/file.go | 106 +- src/pkg/debug/elf/file_test.go | 6 + .../elf/testdata/go-relocation-test-clang-x86.obj | Bin 0 -> 1900 bytes src/pkg/debug/elf/testdata/hello.c | 7 + src/pkg/debug/gosym/pclntab.go | 27 + src/pkg/debug/gosym/symtab.go | 7 + src/pkg/debug/macho/fat.go | 146 + src/pkg/debug/macho/file.go | 23 +- src/pkg/debug/macho/file_test.go | 43 + src/pkg/debug/macho/macho.go | 23 +- .../macho/testdata/fat-gcc-386-amd64-darwin-exec | Bin 0 -> 28992 bytes src/pkg/debug/pe/file.go | 56 +- src/pkg/debug/pe/file_test.go | 139 +- src/pkg/debug/pe/pe.go | 72 + src/pkg/debug/pe/testdata/gcc-amd64-mingw-exec | Bin 0 -> 37376 bytes src/pkg/debug/pe/testdata/gcc-amd64-mingw-obj | Bin 0 -> 736 bytes src/pkg/debug/plan9obj/file.go | 325 + src/pkg/debug/plan9obj/file_test.go | 81 + src/pkg/debug/plan9obj/plan9obj.go | 36 + src/pkg/debug/plan9obj/testdata/386-plan9-exec | Bin 0 -> 37232 bytes src/pkg/debug/plan9obj/testdata/amd64-plan9-exec | Bin 0 -> 34279 bytes src/pkg/debug/plan9obj/testdata/hello.c | 8 + src/pkg/encoding/ascii85/ascii85.go | 12 + src/pkg/encoding/ascii85/ascii85_test.go | 21 +- src/pkg/encoding/asn1/asn1.go | 43 +- src/pkg/encoding/asn1/asn1_test.go | 75 + src/pkg/encoding/asn1/marshal.go | 57 +- src/pkg/encoding/asn1/marshal_test.go | 9 + src/pkg/encoding/base32/base32.go | 12 +- src/pkg/encoding/base32/base32_test.go | 8 +- src/pkg/encoding/base64/base64.go | 39 +- src/pkg/encoding/base64/base64_test.go | 27 +- src/pkg/encoding/binary/binary.go | 1 + src/pkg/encoding/binary/binary_test.go | 28 +- src/pkg/encoding/binary/varint_test.go | 8 +- src/pkg/encoding/csv/reader.go | 6 - src/pkg/encoding/csv/writer_test.go | 2 + src/pkg/encoding/gob/codec_test.go | 56 +- src/pkg/encoding/gob/decode.go | 21 +- src/pkg/encoding/gob/decoder.go | 8 +- src/pkg/encoding/gob/encode.go | 2 +- src/pkg/encoding/gob/encoder_test.go | 4 +- src/pkg/encoding/gob/gobencdec_test.go | 19 +- src/pkg/encoding/hex/hex.go | 3 + src/pkg/encoding/hex/hex_test.go | 6 +- src/pkg/encoding/json/decode.go | 16 +- src/pkg/encoding/json/decode_test.go | 42 +- src/pkg/encoding/json/encode.go | 41 +- src/pkg/encoding/json/encode_test.go | 31 +- src/pkg/encoding/json/example_test.go | 32 + src/pkg/encoding/json/fold.go | 143 + src/pkg/encoding/json/fold_test.go | 116 + src/pkg/encoding/json/indent.go | 5 +- src/pkg/encoding/json/scanner_test.go | 22 +- src/pkg/encoding/json/stream.go | 5 +- src/pkg/encoding/xml/marshal.go | 11 +- src/pkg/encoding/xml/marshal_test.go | 115 + src/pkg/encoding/xml/read.go | 11 +- src/pkg/encoding/xml/read_test.go | 27 + src/pkg/encoding/xml/typeinfo.go | 3 + src/pkg/encoding/xml/xml.go | 2 + src/pkg/expvar/expvar.go | 62 +- src/pkg/expvar/expvar_test.go | 32 +- src/pkg/flag/flag.go | 6 +- src/pkg/fmt/doc.go | 58 +- src/pkg/fmt/fmt_test.go | 234 +- src/pkg/fmt/format.go | 139 +- src/pkg/fmt/print.go | 53 +- src/pkg/fmt/scan.go | 10 +- src/pkg/go/ast/commentmap.go | 2 +- src/pkg/go/ast/example_test.go | 74 + src/pkg/go/build/build.go | 17 +- src/pkg/go/build/deps_test.go | 17 +- src/pkg/go/build/doc.go | 9 +- src/pkg/go/build/syslist.go | 4 +- src/pkg/go/doc/comment.go | 49 +- src/pkg/go/doc/comment_test.go | 106 +- src/pkg/go/doc/example.go | 15 +- src/pkg/go/parser/error_test.go | 21 +- src/pkg/go/parser/interface.go | 7 + src/pkg/go/parser/parser.go | 75 +- src/pkg/go/parser/parser_test.go | 15 +- src/pkg/go/parser/short_test.go | 25 +- src/pkg/go/printer/nodes.go | 72 +- src/pkg/go/printer/printer.go | 125 +- src/pkg/go/printer/printer_test.go | 6 +- src/pkg/go/printer/testdata/comments.golden | 13 +- src/pkg/go/printer/testdata/comments.input | 12 +- src/pkg/go/printer/testdata/comments2.golden | 26 + src/pkg/go/printer/testdata/comments2.input | 28 +- src/pkg/go/printer/testdata/declarations.golden | 18 +- src/pkg/go/printer/testdata/declarations.input | 21 +- src/pkg/go/scanner/scanner.go | 118 +- src/pkg/go/scanner/scanner_test.go | 103 +- src/pkg/hash/crc32/crc32_amd64.go | 25 - src/pkg/hash/crc32/crc32_amd64p32.s | 64 + src/pkg/hash/crc32/crc32_amd64x.go | 27 + src/pkg/hash/fnv/fnv.go | 3 +- src/pkg/html/escape_test.go | 18 + src/pkg/html/template/attr.go | 4 +- src/pkg/html/template/content.go | 3 +- src/pkg/html/template/context.go | 4 +- src/pkg/html/template/escape.go | 52 +- src/pkg/html/template/escape_test.go | 32 + src/pkg/html/template/html.go | 4 +- src/pkg/html/template/js.go | 2 +- src/pkg/html/template/template.go | 8 + src/pkg/image/color/palette/gen.go | 4 + src/pkg/image/color/palette/palette.go | 4 + src/pkg/image/gif/reader.go | 22 +- src/pkg/image/gif/reader_test.go | 4 + src/pkg/image/jpeg/huffman.go | 6 + src/pkg/image/jpeg/reader_test.go | 27 +- src/pkg/image/jpeg/scan.go | 21 +- src/pkg/image/png/reader.go | 10 +- .../video-001.separate.dc.progression.jpeg | Bin 0 -> 14288 bytes ...eo-001.separate.dc.progression.progressive.jpeg | Bin 0 -> 14312 bytes src/pkg/io/io.go | 1 + src/pkg/io/io_test.go | 20 + src/pkg/io/ioutil/blackhole.go | 23 - src/pkg/io/ioutil/ioutil.go | 14 +- src/pkg/io/multi.go | 11 +- src/pkg/io/multi_test.go | 27 + src/pkg/log/example_test.go | 21 + src/pkg/log/syslog/syslog.go | 5 +- src/pkg/log/syslog/syslog_test.go | 2 +- src/pkg/log/syslog/syslog_unix.go | 2 +- src/pkg/math/abs_amd64p32.s | 5 + src/pkg/math/asin_amd64p32.s | 5 + src/pkg/math/atan2_amd64p32.s | 5 + src/pkg/math/atan_amd64p32.s | 5 + src/pkg/math/big/arith.go | 14 +- src/pkg/math/big/arith_amd64p32.s | 41 + src/pkg/math/big/arith_arm.s | 109 +- src/pkg/math/big/int.go | 37 +- src/pkg/math/big/int_test.go | 66 + src/pkg/math/big/nat.go | 11 +- src/pkg/math/big/nat_test.go | 27 +- src/pkg/math/big/rat.go | 21 +- src/pkg/math/big/rat_test.go | 65 + src/pkg/math/cmplx/cmath_test.go | 13 + src/pkg/math/cmplx/pow.go | 18 + src/pkg/math/cmplx/sqrt.go | 1 + src/pkg/math/dim_amd64p32.s | 5 + src/pkg/math/exp2_amd64p32.s | 5 + src/pkg/math/exp_amd64p32.s | 5 + src/pkg/math/expm1_amd64p32.s | 5 + src/pkg/math/floor_amd64p32.s | 5 + src/pkg/math/frexp_amd64p32.s | 5 + src/pkg/math/hypot_amd64p32.s | 5 + src/pkg/math/ldexp_amd64p32.s | 5 + src/pkg/math/log10_amd64p32.s | 5 + src/pkg/math/log1p_amd64p32.s | 5 + src/pkg/math/log_amd64p32.s | 5 + src/pkg/math/mod_amd64p32.s | 5 + src/pkg/math/modf_amd64p32.s | 5 + src/pkg/math/rand/rand.go | 52 +- src/pkg/math/rand/rand_test.go | 39 + src/pkg/math/rand/regress_test.go | 355 + src/pkg/math/remainder_amd64p32.s | 5 + src/pkg/math/sin_amd64p32.s | 5 + src/pkg/math/sincos_amd64p32.s | 5 + src/pkg/math/sqrt_amd64p32.s | 5 + src/pkg/math/tan_amd64p32.s | 5 + src/pkg/mime/mediatype.go | 10 +- src/pkg/mime/mediatype_test.go | 1 + src/pkg/mime/multipart/example_test.go | 53 + src/pkg/mime/multipart/formdata_test.go | 3 +- src/pkg/mime/multipart/multipart.go | 10 +- src/pkg/mime/multipart/quotedprintable_test.go | 2 +- src/pkg/mime/type_unix.go | 2 +- src/pkg/net/cgo_bsd.go | 2 +- src/pkg/net/cgo_unix_test.go | 24 + src/pkg/net/conn_test.go | 39 +- src/pkg/net/dial.go | 25 +- src/pkg/net/dial_test.go | 93 +- src/pkg/net/dialgoogle_test.go | 26 +- src/pkg/net/dnsclient.go | 4 +- src/pkg/net/dnsclient_test.go | 69 + src/pkg/net/dnsclient_unix.go | 103 +- src/pkg/net/dnsclient_unix_test.go | 134 +- src/pkg/net/dnsconfig_unix.go | 9 +- src/pkg/net/dnsconfig_unix_test.go | 46 + src/pkg/net/fd_mutex_test.go | 27 +- src/pkg/net/fd_plan9.go | 115 +- src/pkg/net/fd_poll_nacl.go | 94 + src/pkg/net/fd_poll_runtime.go | 7 +- src/pkg/net/fd_unix.go | 58 +- src/pkg/net/fd_unix_test.go | 2 +- src/pkg/net/fd_windows.go | 14 +- src/pkg/net/file_plan9.go | 10 +- src/pkg/net/file_test.go | 8 +- src/pkg/net/file_unix.go | 4 +- src/pkg/net/hosts_test.go | 2 +- src/pkg/net/http/cgi/host.go | 27 + src/pkg/net/http/cgi/matryoshka_test.go | 137 +- src/pkg/net/http/chunked.go | 58 +- src/pkg/net/http/chunked_test.go | 112 +- src/pkg/net/http/client.go | 111 +- src/pkg/net/http/client_test.go | 275 +- src/pkg/net/http/cookie.go | 58 +- src/pkg/net/http/cookie_test.go | 107 +- src/pkg/net/http/export_test.go | 18 +- src/pkg/net/http/fcgi/child.go | 19 +- src/pkg/net/http/fs.go | 18 +- src/pkg/net/http/fs_test.go | 70 +- src/pkg/net/http/header.go | 19 +- src/pkg/net/http/header_test.go | 9 +- src/pkg/net/http/httptest/server_test.go | 23 + src/pkg/net/http/httputil/chunked.go | 74 +- src/pkg/net/http/httputil/chunked_test.go | 120 +- src/pkg/net/http/httputil/dump.go | 35 +- src/pkg/net/http/httputil/dump_test.go | 87 +- src/pkg/net/http/httputil/httputil.go | 32 + src/pkg/net/http/httputil/persist.go | 21 +- src/pkg/net/http/httputil/reverseproxy.go | 4 + src/pkg/net/http/httputil/reverseproxy_test.go | 16 + src/pkg/net/http/proxy_test.go | 19 +- src/pkg/net/http/race.go | 11 + src/pkg/net/http/request.go | 139 +- src/pkg/net/http/request_test.go | 133 +- src/pkg/net/http/requestwrite_test.go | 42 +- src/pkg/net/http/response.go | 68 +- src/pkg/net/http/response_test.go | 20 +- src/pkg/net/http/responsewrite_test.go | 123 +- src/pkg/net/http/serve_test.go | 586 +- src/pkg/net/http/server.go | 270 +- src/pkg/net/http/transfer.go | 155 +- src/pkg/net/http/transfer_test.go | 33 +- src/pkg/net/http/transport.go | 393 +- src/pkg/net/http/transport_test.go | 529 +- src/pkg/net/interface.go | 10 +- src/pkg/net/interface_linux.go | 58 +- src/pkg/net/interface_stub.go | 2 +- src/pkg/net/ip.go | 3 + src/pkg/net/ip_test.go | 1 + src/pkg/net/ipraw_test.go | 4 +- src/pkg/net/iprawsock_posix.go | 18 +- src/pkg/net/ipsock.go | 6 +- src/pkg/net/ipsock_plan9.go | 66 +- src/pkg/net/ipsock_posix.go | 9 +- src/pkg/net/lookup_plan9.go | 46 +- src/pkg/net/lookup_unix.go | 2 +- src/pkg/net/mail/message.go | 20 +- src/pkg/net/mail/message_test.go | 17 + src/pkg/net/multicast_test.go | 8 +- src/pkg/net/net.go | 15 +- src/pkg/net/net_test.go | 25 +- src/pkg/net/net_windows_test.go | 4 +- src/pkg/net/netgo_unix_test.go | 24 + src/pkg/net/packetconn_test.go | 32 +- src/pkg/net/parse.go | 2 +- src/pkg/net/port_unix.go | 12 +- src/pkg/net/protoconn_test.go | 6 +- src/pkg/net/rpc/client.go | 14 +- src/pkg/net/rpc/client_test.go | 36 + src/pkg/net/rpc/jsonrpc/all_test.go | 35 + src/pkg/net/rpc/jsonrpc/server.go | 6 +- src/pkg/net/rpc/server.go | 5 +- src/pkg/net/rpc/server_test.go | 38 +- src/pkg/net/sendfile_dragonfly.go | 2 +- src/pkg/net/sendfile_freebsd.go | 2 +- src/pkg/net/sendfile_stub.go | 2 +- src/pkg/net/server_test.go | 86 +- src/pkg/net/smtp/example_test.go | 61 + src/pkg/net/smtp/smtp.go | 8 +- src/pkg/net/smtp/smtp_test.go | 144 + src/pkg/net/sock_bsd.go | 2 +- src/pkg/net/sock_cloexec.go | 47 +- src/pkg/net/sock_posix.go | 2 +- src/pkg/net/sock_solaris.go | 13 + src/pkg/net/sockopt_bsd.go | 15 +- src/pkg/net/sockopt_plan9.go | 13 + src/pkg/net/sockopt_posix.go | 2 +- src/pkg/net/sockopt_solaris.go | 32 + src/pkg/net/sockoptip_bsd.go | 2 +- src/pkg/net/sockoptip_posix.go | 2 +- src/pkg/net/sockoptip_stub.go | 39 + src/pkg/net/sys_cloexec.go | 18 +- src/pkg/net/tcp_test.go | 53 +- src/pkg/net/tcpsock_plan9.go | 29 +- src/pkg/net/tcpsock_posix.go | 21 +- src/pkg/net/tcpsockopt_dragonfly.go | 29 + src/pkg/net/tcpsockopt_plan9.go | 18 + src/pkg/net/tcpsockopt_posix.go | 2 +- src/pkg/net/tcpsockopt_solaris.go | 27 + src/pkg/net/tcpsockopt_unix.go | 2 +- src/pkg/net/tcpsockopt_windows.go | 17 +- src/pkg/net/testdata/resolv.conf | 5 + src/pkg/net/textproto/reader.go | 112 +- src/pkg/net/textproto/reader_test.go | 28 +- src/pkg/net/timeout_test.go | 25 +- src/pkg/net/udp_test.go | 4 + src/pkg/net/udpsock.go | 4 - src/pkg/net/udpsock_plan9.go | 3 +- src/pkg/net/udpsock_posix.go | 10 +- src/pkg/net/unicast_posix_test.go | 7 +- src/pkg/net/unix_test.go | 69 +- src/pkg/net/unixsock_posix.go | 28 +- src/pkg/net/url/url.go | 2 +- src/pkg/net/url/url_test.go | 11 + src/pkg/net/z_last_test.go | 37 + src/pkg/os/dir_unix.go | 2 +- src/pkg/os/doc.go | 3 + src/pkg/os/env_unix_test.go | 2 +- src/pkg/os/error_unix.go | 2 +- src/pkg/os/exec/exec.go | 88 +- src/pkg/os/exec/exec_test.go | 151 +- src/pkg/os/exec/lp_unix.go | 2 +- src/pkg/os/exec/lp_unix_test.go | 2 +- src/pkg/os/exec/lp_windows_test.go | 474 +- src/pkg/os/exec_plan9.go | 9 +- src/pkg/os/exec_posix.go | 2 +- src/pkg/os/exec_unix.go | 5 +- src/pkg/os/file.go | 8 + src/pkg/os/file_plan9.go | 33 +- src/pkg/os/file_posix.go | 7 +- src/pkg/os/file_unix.go | 59 +- src/pkg/os/file_windows.go | 15 +- src/pkg/os/getwd.go | 28 +- src/pkg/os/os_test.go | 156 +- src/pkg/os/os_unix_test.go | 40 +- src/pkg/os/path_test.go | 5 +- src/pkg/os/path_unix.go | 2 +- src/pkg/os/pipe_bsd.go | 2 +- src/pkg/os/signal/example_test.go | 4 + src/pkg/os/signal/sig.s | 2 +- src/pkg/os/signal/signal_test.go | 2 +- src/pkg/os/signal/signal_unix.go | 2 +- src/pkg/os/signal/signal_windows_test.go | 11 +- src/pkg/os/stat_nacl.go | 62 + src/pkg/os/stat_solaris.go | 61 + src/pkg/os/sys_bsd.go | 2 +- src/pkg/os/sys_darwin.go | 31 + src/pkg/os/sys_freebsd.go | 23 + src/pkg/os/sys_nacl.go | 9 + src/pkg/os/sys_solaris.go | 11 + src/pkg/os/sys_unix.go | 11 + src/pkg/os/user/lookup_unix.go | 2 +- src/pkg/path/filepath/export_test.go | 7 + src/pkg/path/filepath/match.go | 2 +- src/pkg/path/filepath/match_test.go | 53 +- src/pkg/path/filepath/path.go | 38 +- src/pkg/path/filepath/path_test.go | 63 +- src/pkg/path/filepath/path_unix.go | 2 +- src/pkg/path/filepath/path_windows_test.go | 4 + src/pkg/reflect/all_test.go | 223 + src/pkg/reflect/asm_amd64p32.s | 27 + src/pkg/reflect/deepequal.go | 3 - src/pkg/reflect/export_test.go | 1 + src/pkg/reflect/makefunc.go | 8 +- src/pkg/reflect/type.go | 131 +- src/pkg/reflect/value.go | 968 +- src/pkg/regexp/all_test.go | 65 + src/pkg/regexp/example_test.go | 4 + src/pkg/regexp/exec.go | 121 +- src/pkg/regexp/onepass.go | 582 + src/pkg/regexp/onepass_test.go | 208 + src/pkg/regexp/regexp.go | 20 +- src/pkg/regexp/syntax/doc.go | 4 + src/pkg/regexp/syntax/make_perl_groups.pl | 4 + src/pkg/regexp/syntax/parse.go | 3 +- src/pkg/regexp/syntax/parse_test.go | 4 +- src/pkg/regexp/syntax/perl_groups.go | 4 + src/pkg/regexp/syntax/prog.go | 54 +- src/pkg/regexp/syntax/prog_test.go | 4 +- src/pkg/runtime/alg.c | 541 - src/pkg/runtime/alg.goc | 549 + src/pkg/runtime/append_test.go | 19 + src/pkg/runtime/arch_386.h | 5 + src/pkg/runtime/arch_amd64.h | 9 + src/pkg/runtime/arch_amd64p32.h | 16 + src/pkg/runtime/arch_arm.h | 1 + src/pkg/runtime/asm_386.s | 849 +- src/pkg/runtime/asm_amd64.s | 893 +- src/pkg/runtime/asm_amd64p32.s | 1073 ++ src/pkg/runtime/asm_arm.s | 477 +- src/pkg/runtime/atomic_amd64.c | 27 - src/pkg/runtime/atomic_amd64x.c | 29 + src/pkg/runtime/atomic_arm.c | 13 + src/pkg/runtime/callback_windows.c | 3 +- src/pkg/runtime/cgo/asm_nacl_amd64p32.s | 13 + src/pkg/runtime/cgo/gcc_dragonfly_386.c | 4 +- src/pkg/runtime/cgo/gcc_dragonfly_amd64.c | 4 +- src/pkg/runtime/cgo/gcc_freebsd_386.c | 4 +- src/pkg/runtime/cgo/gcc_freebsd_amd64.c | 4 +- src/pkg/runtime/cgo/gcc_freebsd_arm.c | 9 + src/pkg/runtime/cgo/gcc_linux_386.c | 4 +- src/pkg/runtime/cgo/gcc_linux_amd64.c | 4 +- src/pkg/runtime/cgo/gcc_linux_arm.c | 8 + src/pkg/runtime/cgo/gcc_netbsd_386.c | 4 +- src/pkg/runtime/cgo/gcc_netbsd_amd64.c | 4 +- src/pkg/runtime/cgo/gcc_netbsd_arm.c | 4 +- src/pkg/runtime/cgo/gcc_openbsd_386.c | 4 +- src/pkg/runtime/cgo/gcc_openbsd_amd64.c | 4 +- src/pkg/runtime/cgo/gcc_windows_386.c | 16 +- src/pkg/runtime/cgo/gcc_windows_amd64.c | 14 +- src/pkg/runtime/cgo/libcgo.h | 1 + src/pkg/runtime/cgocall.c | 53 +- src/pkg/runtime/chan.c | 1377 -- src/pkg/runtime/chan.goc | 1155 ++ src/pkg/runtime/chan.h | 75 + src/pkg/runtime/chan_test.go | 637 +- src/pkg/runtime/complex.c | 62 - src/pkg/runtime/complex.goc | 58 + src/pkg/runtime/cpuprof.c | 436 - src/pkg/runtime/cpuprof.goc | 433 + src/pkg/runtime/crash_test.go | 96 +- src/pkg/runtime/debug/garbage.go | 20 +- src/pkg/runtime/debug/heapdump_test.go | 33 + src/pkg/runtime/debug/stack.go | 6 + src/pkg/runtime/defs.c | 14 + src/pkg/runtime/defs_freebsd.go | 6 +- src/pkg/runtime/defs_freebsd_386.h | 6 +- src/pkg/runtime/defs_freebsd_amd64.h | 6 +- src/pkg/runtime/defs_freebsd_arm.h | 36 +- src/pkg/runtime/defs_nacl_386.h | 63 + src/pkg/runtime/defs_nacl_amd64p32.h | 90 + src/pkg/runtime/defs_openbsd_386.h | 8 +- src/pkg/runtime/defs_openbsd_amd64.h | 9 +- src/pkg/runtime/defs_solaris.go | 156 + src/pkg/runtime/defs_solaris_amd64.go | 48 + src/pkg/runtime/defs_solaris_amd64.h | 254 + src/pkg/runtime/env_plan9.c | 10 +- src/pkg/runtime/env_posix.c | 17 +- src/pkg/runtime/error.go | 7 +- src/pkg/runtime/export_test.c | 13 - src/pkg/runtime/export_test.go | 34 +- src/pkg/runtime/extern.go | 28 +- src/pkg/runtime/funcdata.h | 6 +- src/pkg/runtime/futex_test.go | 75 +- src/pkg/runtime/gc_test.go | 83 + src/pkg/runtime/hash_test.go | 6 +- src/pkg/runtime/hashmap.c | 1367 -- src/pkg/runtime/hashmap.goc | 1078 ++ src/pkg/runtime/hashmap.h | 147 + src/pkg/runtime/hashmap_fast.c | 90 +- src/pkg/runtime/heapdump.c | 981 ++ src/pkg/runtime/iface.c | 721 - src/pkg/runtime/iface.goc | 620 + src/pkg/runtime/lfstack.c | 65 - src/pkg/runtime/lfstack.goc | 81 + src/pkg/runtime/lfstack_test.go | 12 +- src/pkg/runtime/lock_futex.c | 12 +- src/pkg/runtime/lock_sema.c | 11 +- src/pkg/runtime/malloc.goc | 604 +- src/pkg/runtime/malloc.h | 215 +- src/pkg/runtime/map_test.go | 66 + src/pkg/runtime/mapspeed_test.go | 30 + src/pkg/runtime/mcache.c | 123 +- src/pkg/runtime/mcentral.c | 205 +- src/pkg/runtime/mem.go | 3 +- src/pkg/runtime/mem_darwin.c | 13 +- src/pkg/runtime/mem_dragonfly.c | 19 +- src/pkg/runtime/mem_freebsd.c | 19 +- src/pkg/runtime/mem_linux.c | 30 +- src/pkg/runtime/mem_nacl.c | 118 + src/pkg/runtime/mem_netbsd.c | 17 +- src/pkg/runtime/mem_openbsd.c | 17 +- src/pkg/runtime/mem_plan9.c | 13 +- src/pkg/runtime/mem_solaris.c | 99 + src/pkg/runtime/mem_windows.c | 43 +- src/pkg/runtime/memclr_386.s | 127 + src/pkg/runtime/memclr_amd64.s | 116 + src/pkg/runtime/memclr_arm.s | 6 - src/pkg/runtime/memclr_plan9_386.s | 50 + src/pkg/runtime/memclr_plan9_amd64.s | 48 + src/pkg/runtime/memmove_386.s | 2 + src/pkg/runtime/memmove_amd64.s | 2 + src/pkg/runtime/memmove_nacl_amd64p32.s | 46 + src/pkg/runtime/memmove_plan9_386.s | 127 + src/pkg/runtime/memmove_plan9_amd64.s | 126 + src/pkg/runtime/memmove_test.go | 179 +- src/pkg/runtime/mfinal.c | 219 - src/pkg/runtime/mfinal_test.go | 175 +- src/pkg/runtime/mgc0.c | 1814 ++- src/pkg/runtime/mgc0.go | 12 + src/pkg/runtime/mgc0.h | 41 + src/pkg/runtime/mheap.c | 506 +- src/pkg/runtime/mknacl.sh | 15 + src/pkg/runtime/mprof.goc | 271 +- src/pkg/runtime/msize.c | 36 +- src/pkg/runtime/netpoll.goc | 169 +- src/pkg/runtime/netpoll_epoll.c | 7 + src/pkg/runtime/netpoll_kqueue.c | 7 + src/pkg/runtime/netpoll_nacl.c | 37 + src/pkg/runtime/netpoll_solaris.c | 268 + src/pkg/runtime/netpoll_windows.c | 15 + src/pkg/runtime/norace_test.go | 36 +- src/pkg/runtime/os_darwin.c | 14 +- src/pkg/runtime/os_darwin.h | 2 +- src/pkg/runtime/os_dragonfly.c | 14 +- src/pkg/runtime/os_dragonfly.h | 1 + src/pkg/runtime/os_freebsd.c | 20 +- src/pkg/runtime/os_freebsd.h | 1 + src/pkg/runtime/os_linux.c | 13 +- src/pkg/runtime/os_linux.h | 1 + src/pkg/runtime/os_linux_arm.c | 2 +- src/pkg/runtime/os_nacl.c | 278 + src/pkg/runtime/os_nacl.h | 162 + src/pkg/runtime/os_netbsd.c | 14 +- src/pkg/runtime/os_netbsd.h | 1 + src/pkg/runtime/os_openbsd.c | 16 +- src/pkg/runtime/os_openbsd.h | 1 + src/pkg/runtime/os_plan9.c | 101 +- src/pkg/runtime/os_plan9.h | 9 +- src/pkg/runtime/os_plan9_386.c | 135 +- src/pkg/runtime/os_plan9_amd64.c | 106 +- src/pkg/runtime/os_solaris.c | 583 + src/pkg/runtime/os_solaris.h | 51 + src/pkg/runtime/os_windows.c | 101 +- src/pkg/runtime/os_windows_386.c | 48 +- src/pkg/runtime/os_windows_amd64.c | 44 +- src/pkg/runtime/panic.c | 326 +- src/pkg/runtime/parfor.c | 28 +- src/pkg/runtime/pprof/pprof.go | 2 +- src/pkg/runtime/pprof/pprof_test.go | 29 +- src/pkg/runtime/print.c | 63 +- src/pkg/runtime/proc.c | 717 +- src/pkg/runtime/proc.p | 526 - src/pkg/runtime/proc_test.go | 66 +- src/pkg/runtime/race.c | 394 +- src/pkg/runtime/race.h | 3 +- src/pkg/runtime/race/README | 2 +- src/pkg/runtime/race/race.go | 118 +- src/pkg/runtime/race/race_darwin_amd64.syso | Bin 192988 -> 222964 bytes src/pkg/runtime/race/race_linux_amd64.syso | Bin 195144 -> 243208 bytes src/pkg/runtime/race/race_test.go | 17 +- src/pkg/runtime/race/race_windows_amd64.syso | Bin 161295 -> 210859 bytes src/pkg/runtime/race/testdata/chan_test.go | 207 +- src/pkg/runtime/race/testdata/finalizer_test.go | 22 +- src/pkg/runtime/race/testdata/map_test.go | 79 + src/pkg/runtime/race/testdata/mop_test.go | 22 + src/pkg/runtime/race0.c | 6 - src/pkg/runtime/race_amd64.s | 240 +- src/pkg/runtime/rdebug.goc | 27 + src/pkg/runtime/rt0_freebsd_arm.s | 5 + src/pkg/runtime/rt0_nacl_386.s | 22 + src/pkg/runtime/rt0_nacl_amd64p32.s | 30 + src/pkg/runtime/rt0_solaris_amd64.s | 18 + src/pkg/runtime/runtime-gdb.py | 160 +- src/pkg/runtime/runtime.c | 120 +- src/pkg/runtime/runtime.h | 254 +- src/pkg/runtime/runtime1.goc | 114 + src/pkg/runtime/runtime_test.go | 82 +- src/pkg/runtime/runtime_unix_test.go | 56 + src/pkg/runtime/sema.goc | 6 +- src/pkg/runtime/signal_386.c | 9 +- src/pkg/runtime/signal_amd64.c | 135 - src/pkg/runtime/signal_amd64x.c | 156 + src/pkg/runtime/signal_arm.c | 7 +- src/pkg/runtime/signal_nacl_386.h | 23 + src/pkg/runtime/signal_nacl_amd64p32.h | 31 + src/pkg/runtime/signal_solaris_amd64.h | 31 + src/pkg/runtime/signal_unix.c | 3 +- src/pkg/runtime/signals_freebsd.h | 2 +- src/pkg/runtime/signals_linux.h | 2 +- src/pkg/runtime/signals_nacl.h | 50 + src/pkg/runtime/signals_plan9.h | 60 +- src/pkg/runtime/signals_solaris.h | 94 + src/pkg/runtime/slice.c | 196 - src/pkg/runtime/slice.goc | 204 + src/pkg/runtime/softfloat_arm.c | 4 +- src/pkg/runtime/sqrt.go | 150 + src/pkg/runtime/stack.c | 711 +- src/pkg/runtime/stack.h | 5 +- src/pkg/runtime/stack_gen_test.go | 1473 ++ src/pkg/runtime/stack_test.go | 1661 +-- src/pkg/runtime/string.goc | 102 +- src/pkg/runtime/symtab.c | 333 - src/pkg/runtime/symtab.goc | 332 + src/pkg/runtime/sys_darwin_386.s | 3 +- src/pkg/runtime/sys_dragonfly_386.s | 4 +- src/pkg/runtime/sys_dragonfly_amd64.s | 4 +- src/pkg/runtime/sys_freebsd_386.s | 11 +- src/pkg/runtime/sys_freebsd_amd64.s | 6 +- src/pkg/runtime/sys_freebsd_arm.s | 9 +- src/pkg/runtime/sys_linux_386.s | 6 +- src/pkg/runtime/sys_linux_amd64.s | 4 +- src/pkg/runtime/sys_linux_arm.s | 2 +- src/pkg/runtime/sys_nacl_386.s | 243 + src/pkg/runtime/sys_nacl_amd64p32.s | 413 + src/pkg/runtime/sys_openbsd_386.s | 56 +- src/pkg/runtime/sys_openbsd_amd64.s | 22 +- src/pkg/runtime/sys_plan9_386.s | 15 +- src/pkg/runtime/sys_plan9_amd64.s | 2 +- src/pkg/runtime/sys_solaris_amd64.s | 267 + src/pkg/runtime/sys_windows_386.s | 123 +- src/pkg/runtime/sys_windows_amd64.s | 126 +- src/pkg/runtime/sys_x86.c | 30 +- src/pkg/runtime/syscall_nacl.h | 71 + src/pkg/runtime/syscall_solaris.goc | 374 + src/pkg/runtime/syscall_windows.goc | 19 +- src/pkg/runtime/syscall_windows_test.go | 249 +- src/pkg/runtime/time.goc | 32 +- src/pkg/runtime/traceback_arm.c | 116 +- src/pkg/runtime/traceback_x86.c | 207 +- src/pkg/runtime/type.go | 1 + src/pkg/runtime/type.h | 8 +- src/pkg/runtime/typekind.h | 3 - src/pkg/runtime/vlop_arm.s | 13 +- src/pkg/runtime/vlrt_386.c | 12 + src/pkg/runtime/vlrt_arm.c | 7 +- src/pkg/sort/sort.go | 6 +- src/pkg/strconv/atob_test.go | 34 + src/pkg/strconv/atof.go | 11 - src/pkg/strconv/atoi.go | 8 +- src/pkg/strconv/isprint.go | 4 + src/pkg/strconv/makeisprint.go | 3 + src/pkg/strconv/quote.go | 3 +- src/pkg/strconv/quote_example_test.go | 35 + src/pkg/strconv/quote_test.go | 1 + src/pkg/strings/example_test.go | 32 +- src/pkg/strings/reader.go | 52 +- src/pkg/strings/reader_test.go | 56 +- src/pkg/strings/replace.go | 2 +- src/pkg/strings/strings_test.go | 30 +- src/pkg/sync/atomic/asm_386.s | 14 +- src/pkg/sync/atomic/asm_amd64.s | 4 +- src/pkg/sync/atomic/asm_amd64p32.s | 159 + src/pkg/sync/atomic/asm_linux_arm.s | 12 +- src/pkg/sync/atomic/atomic_test.go | 7 +- src/pkg/sync/atomic/export_linux_arm_test.go | 2 +- src/pkg/sync/mutex_test.go | 72 +- src/pkg/sync/once_test.go | 25 +- src/pkg/sync/pool.go | 223 + src/pkg/sync/pool_test.go | 151 + src/pkg/sync/runtime_sema_test.go | 85 +- src/pkg/sync/rwmutex_test.go | 79 +- src/pkg/sync/waitgroup.go | 10 +- src/pkg/sync/waitgroup_test.go | 125 +- src/pkg/syscall/asm_darwin_386.s | 13 +- src/pkg/syscall/asm_darwin_amd64.s | 11 +- src/pkg/syscall/asm_freebsd_386.s | 13 +- src/pkg/syscall/asm_freebsd_amd64.s | 13 +- src/pkg/syscall/asm_freebsd_arm.s | 51 +- src/pkg/syscall/asm_linux_386.s | 17 +- src/pkg/syscall/asm_linux_amd64.s | 21 +- src/pkg/syscall/asm_linux_arm.s | 4 +- src/pkg/syscall/asm_nacl_386.s | 43 + src/pkg/syscall/asm_nacl_amd64p32.s | 41 + src/pkg/syscall/asm_netbsd_386.s | 13 +- src/pkg/syscall/asm_netbsd_amd64.s | 13 +- src/pkg/syscall/asm_openbsd_386.s | 13 +- src/pkg/syscall/asm_openbsd_amd64.s | 13 +- src/pkg/syscall/asm_plan9_386.s | 9 +- src/pkg/syscall/asm_plan9_amd64.s | 11 +- src/pkg/syscall/asm_solaris_amd64.s | 7 + src/pkg/syscall/consistency_unix_test.go | 34 - src/pkg/syscall/dir_plan9.go | 9 +- src/pkg/syscall/env_unix.go | 2 +- src/pkg/syscall/exec_linux.go | 6 +- src/pkg/syscall/exec_plan9.go | 2 +- src/pkg/syscall/exec_solaris.go | 243 + src/pkg/syscall/exec_unix.go | 4 +- src/pkg/syscall/fd_nacl.go | 326 + src/pkg/syscall/flock.go | 22 + src/pkg/syscall/flock_linux_32bit.go | 13 + src/pkg/syscall/fs_nacl.go | 815 ++ src/pkg/syscall/lsf_linux.go | 4 +- src/pkg/syscall/mkall.sh | 61 +- src/pkg/syscall/mkall_windows.bat | 21 + src/pkg/syscall/mkerrors.sh | 79 +- src/pkg/syscall/mkerrors_windows.sh | 202 - src/pkg/syscall/mksyscall.pl | 10 +- src/pkg/syscall/mksyscall_solaris.pl | 279 + src/pkg/syscall/mksyscall_windows.go | 662 + src/pkg/syscall/mksyscall_windows.pl | 333 - src/pkg/syscall/mksysnum_dragonfly.pl | 2 +- src/pkg/syscall/mksysnum_freebsd.pl | 13 + src/pkg/syscall/mmap_unix_test.go | 22 + src/pkg/syscall/net_nacl.go | 912 ++ src/pkg/syscall/passfd_test.go | 202 - src/pkg/syscall/rlimit_linux_test.go | 41 - src/pkg/syscall/route_bsd.go | 9 +- src/pkg/syscall/route_dragonfly.go | 2 +- src/pkg/syscall/route_freebsd.go | 12 +- src/pkg/syscall/route_freebsd_32bit.go | 24 + src/pkg/syscall/route_freebsd_64bit.go | 14 + src/pkg/syscall/route_netbsd.go | 2 +- src/pkg/syscall/route_openbsd.go | 2 +- src/pkg/syscall/so_solaris.go | 260 + src/pkg/syscall/sockcmsg_unix.go | 8 +- src/pkg/syscall/srpc_nacl.go | 822 ++ src/pkg/syscall/syscall_bsd.go | 98 +- src/pkg/syscall/syscall_bsd_test.go | 34 + src/pkg/syscall/syscall_darwin.go | 21 +- src/pkg/syscall/syscall_dragonfly.go | 16 +- src/pkg/syscall/syscall_freebsd.go | 39 +- src/pkg/syscall/syscall_linux.go | 65 +- src/pkg/syscall/syscall_linux_386.go | 31 +- src/pkg/syscall/syscall_linux_amd64.go | 36 +- src/pkg/syscall/syscall_linux_arm.go | 26 +- src/pkg/syscall/syscall_nacl.go | 311 + src/pkg/syscall/syscall_nacl_386.go | 32 + src/pkg/syscall/syscall_nacl_amd64p32.go | 32 + src/pkg/syscall/syscall_openbsd.go | 22 +- src/pkg/syscall/syscall_openbsd_386.go | 4 +- src/pkg/syscall/syscall_openbsd_amd64.go | 6 +- src/pkg/syscall/syscall_plan9.go | 2 +- src/pkg/syscall/syscall_solaris.go | 523 + src/pkg/syscall/syscall_solaris_amd64.go | 37 + src/pkg/syscall/syscall_unix.go | 31 +- src/pkg/syscall/syscall_unix_test.go | 314 + src/pkg/syscall/syscall_windows.go | 27 +- src/pkg/syscall/tables_nacl.go | 324 + src/pkg/syscall/time_nacl_386.s | 11 + src/pkg/syscall/time_nacl_amd64p32.s | 11 + src/pkg/syscall/types_dragonfly.go | 9 +- src/pkg/syscall/types_freebsd.go | 110 +- src/pkg/syscall/types_linux.go | 2 + src/pkg/syscall/types_netbsd.go | 5 + src/pkg/syscall/types_openbsd.go | 5 + src/pkg/syscall/types_solaris.go | 222 + src/pkg/syscall/unzip_nacl.go | 685 + src/pkg/syscall/zerrors_dragonfly_386.go | 5 +- src/pkg/syscall/zerrors_dragonfly_amd64.go | 5 +- src/pkg/syscall/zerrors_freebsd_386.go | 33 +- src/pkg/syscall/zerrors_freebsd_amd64.go | 34 +- src/pkg/syscall/zerrors_freebsd_arm.go | 35 +- src/pkg/syscall/zerrors_netbsd_386.go | 51 +- src/pkg/syscall/zerrors_netbsd_amd64.go | 51 +- src/pkg/syscall/zerrors_netbsd_arm.go | 36 + src/pkg/syscall/zerrors_openbsd_386.go | 66 +- src/pkg/syscall/zerrors_openbsd_amd64.go | 63 +- src/pkg/syscall/zerrors_solaris_amd64.go | 1414 ++ src/pkg/syscall/zsyscall_darwin_386.go | 102 +- src/pkg/syscall/zsyscall_darwin_amd64.go | 102 +- src/pkg/syscall/zsyscall_dragonfly_386.go | 34 +- src/pkg/syscall/zsyscall_dragonfly_amd64.go | 34 +- src/pkg/syscall/zsyscall_freebsd_386.go | 45 +- src/pkg/syscall/zsyscall_freebsd_amd64.go | 45 +- src/pkg/syscall/zsyscall_freebsd_arm.go | 120 +- src/pkg/syscall/zsyscall_linux_amd64.go | 15 +- src/pkg/syscall/zsyscall_linux_arm.go | 15 +- src/pkg/syscall/zsyscall_nacl_386.go | 63 + src/pkg/syscall/zsyscall_nacl_amd64p32.go | 63 + src/pkg/syscall/zsyscall_netbsd_386.go | 17 +- src/pkg/syscall/zsyscall_netbsd_amd64.go | 17 +- src/pkg/syscall/zsyscall_netbsd_arm.go | 28 +- src/pkg/syscall/zsyscall_openbsd_386.go | 68 +- src/pkg/syscall/zsyscall_openbsd_amd64.go | 68 +- src/pkg/syscall/zsyscall_solaris_amd64.go | 883 ++ src/pkg/syscall/zsyscall_windows_386.go | 6 +- src/pkg/syscall/zsyscall_windows_amd64.go | 6 +- src/pkg/syscall/zsysctl_openbsd.go | 28 +- src/pkg/syscall/zsysnum_dragonfly_386.go | 5 +- src/pkg/syscall/zsysnum_dragonfly_amd64.go | 5 +- src/pkg/syscall/zsysnum_freebsd_386.go | 20 +- src/pkg/syscall/zsysnum_freebsd_amd64.go | 20 +- src/pkg/syscall/zsysnum_freebsd_arm.go | 27 +- src/pkg/syscall/zsysnum_openbsd_386.go | 57 +- src/pkg/syscall/zsysnum_openbsd_amd64.go | 57 +- src/pkg/syscall/zsysnum_solaris_amd64.go | 11 + src/pkg/syscall/ztypes_dragonfly_386.go | 14 +- src/pkg/syscall/ztypes_dragonfly_amd64.go | 14 +- src/pkg/syscall/ztypes_freebsd_386.go | 55 +- src/pkg/syscall/ztypes_freebsd_amd64.go | 55 +- src/pkg/syscall/ztypes_freebsd_arm.go | 120 +- src/pkg/syscall/ztypes_linux_386.go | 8 + src/pkg/syscall/ztypes_linux_amd64.go | 10 + src/pkg/syscall/ztypes_linux_arm.go | 10 + src/pkg/syscall/ztypes_netbsd_386.go | 10 + src/pkg/syscall/ztypes_netbsd_amd64.go | 10 + src/pkg/syscall/ztypes_netbsd_arm.go | 39 +- src/pkg/syscall/ztypes_openbsd_386.go | 55 +- src/pkg/syscall/ztypes_openbsd_amd64.go | 56 +- src/pkg/syscall/ztypes_solaris_amd64.go | 365 + src/pkg/syscall/ztypes_windows.go | 9 + src/pkg/testing/benchmark.go | 102 +- src/pkg/testing/benchmark_test.go | 53 + src/pkg/testing/testing.go | 47 +- src/pkg/text/scanner/scanner.go | 6 +- src/pkg/text/scanner/scanner_test.go | 41 +- src/pkg/text/tabwriter/tabwriter.go | 12 +- src/pkg/text/tabwriter/tabwriter_test.go | 39 +- src/pkg/text/template/doc.go | 2 +- src/pkg/text/template/exec.go | 11 + src/pkg/text/template/exec_test.go | 30 +- src/pkg/text/template/multi_test.go | 12 + src/pkg/text/template/template.go | 2 +- src/pkg/time/format.go | 9 +- src/pkg/time/format_test.go | 511 + src/pkg/time/internal_test.go | 20 +- src/pkg/time/sleep.go | 12 +- src/pkg/time/sleep_test.go | 31 +- src/pkg/time/sys_unix.go | 2 +- src/pkg/time/tick.go | 3 +- src/pkg/time/tick_test.go | 18 + src/pkg/time/time.go | 2 + src/pkg/time/time_test.go | 553 +- src/pkg/time/zoneinfo.go | 87 +- src/pkg/time/zoneinfo_plan9.go | 2 +- src/pkg/time/zoneinfo_read.go | 8 +- src/pkg/time/zoneinfo_test.go | 63 + src/pkg/time/zoneinfo_unix.go | 2 +- src/pkg/time/zoneinfo_windows.go | 8 +- src/pkg/unicode/letter.go | 4 +- src/pkg/unicode/letter_test.go | 16 +- src/pkg/unicode/maketables.go | 8 +- src/pkg/unicode/script_test.go | 2 +- src/pkg/unicode/tables.go | 65 +- src/pkg/unicode/utf16/utf16.go | 2 +- src/pkg/unicode/utf16/utf16_test.go | 48 + src/pkg/unicode/utf8/example_test.go | 4 + src/pkg/unicode/utf8/utf8.go | 32 +- src/race.bash | 6 + src/race.bat | 10 +- src/run.bash | 54 +- src/run.bat | 17 +- src/run.rc | 8 +- test/bench/shootout/threadring.c | 12 +- test/bench/shootout/timing.sh | 157 +- test/cmp.go | 59 + test/cmp6.go | 13 +- test/const1.go | 8 +- test/const5.go | 4 + test/deferfin.go | 12 +- test/divmod.go | 2 +- test/escape2.go | 155 +- test/escape5.go | 8 +- test/fixedbugs/bug176.go | 2 +- test/fixedbugs/bug191.dir/a.go | 4 +- test/fixedbugs/bug191.dir/b.go | 4 +- test/fixedbugs/bug191.dir/main.go | 3 + test/fixedbugs/bug191.go | 2 +- test/fixedbugs/bug191.out | 2 - test/fixedbugs/bug385_32.go | 4 +- test/fixedbugs/bug385_64.go | 2 +- test/fixedbugs/bug462.go | 2 +- test/fixedbugs/bug476.go | 2 +- test/fixedbugs/bug480.dir/a.go | 17 + test/fixedbugs/bug480.dir/b.go | 13 + test/fixedbugs/bug480.go | 9 + test/fixedbugs/bug481.go | 18 + test/fixedbugs/bug482.go | 20 + test/fixedbugs/bug483.go | 36 + test/fixedbugs/bug484.go | 90 + test/fixedbugs/bug485.go | 39 + test/fixedbugs/issue1304.go | 23 + test/fixedbugs/issue3705.go | 2 +- test/fixedbugs/issue4251.go | 6 +- test/fixedbugs/issue4388.go | 56 + test/fixedbugs/issue4405.go | 8 +- test/fixedbugs/issue4429.go | 2 +- test/fixedbugs/issue4510.dir/f1.go | 2 +- test/fixedbugs/issue4517d.go | 2 +- test/fixedbugs/issue4545.go | 2 +- test/fixedbugs/issue4610.go | 4 +- test/fixedbugs/issue4618.go | 5 +- test/fixedbugs/issue4654.go | 44 +- test/fixedbugs/issue4667.go | 4 +- test/fixedbugs/issue4776.go | 2 +- test/fixedbugs/issue4813.go | 12 +- test/fixedbugs/issue4847.go | 2 +- test/fixedbugs/issue5089.go | 4 +- test/fixedbugs/issue5172.go | 4 +- test/fixedbugs/issue5358.go | 2 +- test/fixedbugs/issue5493.go | 5 +- test/fixedbugs/issue5581.go | 2 +- test/fixedbugs/issue5793.go | 36 + test/fixedbugs/issue5957.dir/c.go | 10 +- test/fixedbugs/issue6295.dir/p0.go | 13 + test/fixedbugs/issue6295.dir/p1.go | 26 + test/fixedbugs/issue6295.dir/p2.go | 19 + test/fixedbugs/issue6295.go | 10 + test/fixedbugs/issue6402.go | 13 + test/fixedbugs/issue6403.go | 14 + test/fixedbugs/issue6405.go | 13 + test/fixedbugs/issue6406.go | 12 + test/fixedbugs/issue6500.go | 29 + test/fixedbugs/issue6572.go | 21 + test/fixedbugs/issue6789.dir/a.go | 14 + test/fixedbugs/issue6789.dir/b.go | 12 + test/fixedbugs/issue6789.go | 10 + test/fixedbugs/issue6847.go | 85 + test/fixedbugs/issue6889.go | 103 + test/fixedbugs/issue6899.go | 13 + test/fixedbugs/issue6899.out | 1 + test/fixedbugs/issue6902.go | 21 + test/fixedbugs/issue6964.go | 11 + test/fixedbugs/issue7023.dir/a.go | 10 + test/fixedbugs/issue7023.dir/b.go | 11 + test/fixedbugs/issue7023.go | 10 + test/fixedbugs/issue7044.go | 43 + test/fixedbugs/issue7050.go | 19 + test/fixedbugs/issue7083.go | 22 + test/fixedbugs/issue7129.go | 21 + test/fixedbugs/issue7150.go | 17 + test/fixedbugs/issue7153.go | 11 + test/fixedbugs/issue7214.go | 30 + test/fixedbugs/issue7223.go | 20 + test/fixedbugs/issue7272.go | 48 + test/fixedbugs/issue7310.go | 15 + test/fixedbugs/issue7316.go | 37 + test/fixedbugs/issue7346.go | 14 + test/fixedbugs/issue7366.go | 21 + test/fixedbugs/issue7405.go | 51 + test/fixedbugs/issue7419.go | 25 + test/fixedbugs/issue7525.go | 19 + test/fixedbugs/issue7538a.go | 15 + test/fixedbugs/issue7538b.go | 13 + test/fixedbugs/issue7547.go | 17 + test/fixedbugs/issue7550.go | 27 + test/fixedbugs/issue7590.go | 21 + test/fixedbugs/issue7648.dir/a.go | 11 + test/fixedbugs/issue7648.dir/b.go | 11 + test/fixedbugs/issue7648.go | 9 + test/fixedbugs/issue7675.go | 24 + test/fixedbugs/issue7742.go | 18 + test/fixedbugs/issue7794.go | 12 + test/fixedbugs/issue7863.go | 60 + test/fixedbugs/issue7867.go | 43 + test/fixedbugs/issue7884.go | 15 + test/fixedbugs/issue7944.go | 40 + test/fixedbugs/issue7995.go | 25 + test/fixedbugs/issue7995b.dir/x1.go | 16 + test/fixedbugs/issue7995b.dir/x2.go | 10 + test/fixedbugs/issue7995b.go | 9 + test/fixedbugs/issue7996.go | 14 + test/fixedbugs/issue7997.go | 53 + test/fixedbugs/issue7998.go | 23 + test/fixedbugs/issue8004.go | 59 + test/fixedbugs/issue8011.go | 18 + test/fixedbugs/issue8028.go | 27 + test/fixedbugs/issue8036.go | 45 + test/fixedbugs/issue8039.go | 23 + test/fixedbugs/issue8047.go | 29 + test/fixedbugs/issue8047b.go | 22 + test/fixedbugs/issue8048.go | 107 + test/fixedbugs/issue8073.go | 15 + test/fixedbugs/issue8076.go | 17 + test/fixedbugs/issue8132.go | 32 + test/fixedbugs/issue8139.go | 50 + test/fixedbugs/issue8155.go | 48 + test/fixedbugs/issue8158.go | 41 + test/float_lit2.go | 164 + test/float_lit3.go | 48 + test/funcdup.go | 24 +- test/funcdup2.go | 12 +- test/gc2.go | 4 +- test/gcstring.go | 48 + test/import1.go | 2 +- test/import4.dir/empty.go | 2 +- test/import4.dir/import4.go | 4 +- test/live.go | 624 + test/live1.go | 46 + test/live2.go | 39 + test/method4.dir/prog.go | 9 +- test/nilptr3.go | 102 +- test/nilptr4.go | 24 + test/nosplit.go | 314 + test/reorder2.go | 169 + test/run | 2 +- test/run.go | 139 +- test/sigchld.go | 2 +- test/slice3err.go | 56 +- test/string_lit.go | 5 + test/syntax/semi1.go | 2 +- test/syntax/semi2.go | 2 +- test/syntax/semi3.go | 2 +- test/syntax/semi4.go | 2 +- test/tinyfin.go | 62 + test/typecheck.go | 4 +- 1643 files changed, 135133 insertions(+), 75056 deletions(-) create mode 100644 api/go1.3.txt delete mode 100644 doc/Makefile create mode 100644 doc/articles/race_detector.html delete mode 100644 doc/articles/wiki/Makefile create mode 100644 doc/go1.3.html create mode 100644 doc/gopher/README delete mode 100644 include/bootexec.h create mode 100644 include/link.h delete mode 100644 include/mach.h create mode 100644 include/plan9/bio.h create mode 100644 include/plan9/errno.h create mode 100644 include/plan9/fmt.h create mode 100644 include/plan9/link.h delete mode 100644 include/plan9/mach.h create mode 100755 include/plan9/mklibc.rc create mode 100644 include/plan9/stdarg.h delete mode 100644 include/plan9/ureg_amd64.h delete mode 100644 include/plan9/ureg_arm.h delete mode 100644 include/plan9/ureg_x86.h create mode 100644 include/plan9/utf.h delete mode 100644 include/ureg_amd64.h delete mode 100644 include/ureg_arm.h delete mode 100644 include/ureg_x86.h create mode 100644 misc/cgo/errors/err3.go create mode 100644 misc/cgo/nocgo/nocgo.go create mode 100644 misc/cgo/nocgo/nocgo_test.go create mode 100644 misc/cgo/test/backdoor/backdoor_gccgo.go create mode 100644 misc/cgo/test/issue6833.go create mode 100644 misc/cgo/test/issue6833_c.c create mode 100644 misc/cgo/test/issue6997_linux.c create mode 100644 misc/cgo/test/issue6997_linux.go create mode 100644 misc/cgo/test/issue7234_test.go create mode 100644 misc/cgo/test/issue7560.go create mode 100644 misc/cgo/test/issue7665.go create mode 100644 misc/cgo/test/issue7695_test.go create mode 100644 misc/cgo/test/issue7786.go create mode 100644 misc/cgo/test/issue8148.go create mode 100644 misc/cgo/test/issue8331.h create mode 100644 misc/cgo/test/issue8331a.go create mode 100644 misc/cgo/test/issue8331b.go create mode 100644 misc/cgo/testso/cgoso_unix.go delete mode 100644 misc/dist/bindist.go delete mode 100644 misc/dist/darwin/Distribution delete mode 100644 misc/dist/darwin/Resources/bg.png delete mode 100644 misc/dist/darwin/etc/paths.d/go delete mode 100755 misc/dist/darwin/scripts/postinstall delete mode 100755 misc/dist/darwin/scripts/preinstall delete mode 100644 misc/dist/windows/LICENSE.rtf delete mode 100644 misc/dist/windows/README.txt delete mode 100644 misc/dist/windows/images/Banner.jpg delete mode 100644 misc/dist/windows/images/Dialog.jpg delete mode 100644 misc/dist/windows/images/DialogLeft.jpg delete mode 100644 misc/dist/windows/images/gopher.ico delete mode 100644 misc/dist/windows/installer.wxs delete mode 100644 misc/goplay/Makefile delete mode 100644 misc/goplay/README delete mode 100644 misc/goplay/doc.go delete mode 100644 misc/goplay/goplay.go create mode 100644 misc/makerelease/darwin/Distribution create mode 100644 misc/makerelease/darwin/Resources/bg.png create mode 100644 misc/makerelease/darwin/etc/paths.d/go create mode 100755 misc/makerelease/darwin/scripts/postinstall create mode 100755 misc/makerelease/darwin/scripts/preinstall create mode 100644 misc/makerelease/makerelease.go create mode 100644 misc/makerelease/windows/LICENSE.rtf create mode 100644 misc/makerelease/windows/README.txt create mode 100644 misc/makerelease/windows/images/Banner.jpg create mode 100644 misc/makerelease/windows/images/Dialog.jpg create mode 100644 misc/makerelease/windows/images/DialogLeft.jpg create mode 100644 misc/makerelease/windows/images/gopher.ico create mode 100644 misc/makerelease/windows/installer.wxs create mode 100644 misc/nacl/README create mode 100755 misc/nacl/go_nacl_386_exec create mode 100755 misc/nacl/go_nacl_amd64p32_exec create mode 100644 misc/nacl/mkzip.go create mode 100644 misc/nacl/testdata/bin/placeholder create mode 100644 misc/nacl/testdata/empty create mode 100644 misc/nacl/testdata/group create mode 100644 misc/nacl/testdata/hosts create mode 100644 misc/nacl/testdata/mime.types create mode 100644 misc/nacl/testzip.proto delete mode 100644 src/cmd/5g/list.c delete mode 100644 src/cmd/5l/optab.c delete mode 100644 src/cmd/5l/pass.c delete mode 100644 src/cmd/5l/prof.c delete mode 100644 src/cmd/5l/softfloat.c delete mode 100644 src/cmd/5l/span.c delete mode 100644 src/cmd/6g/list.c delete mode 100644 src/cmd/6l/optab.c delete mode 100644 src/cmd/6l/pass.c delete mode 100644 src/cmd/6l/prof.c delete mode 100644 src/cmd/6l/span.c delete mode 100644 src/cmd/8g/list.c delete mode 100644 src/cmd/8l/optab.c delete mode 100644 src/cmd/8l/pass.c delete mode 100644 src/cmd/8l/prof.c delete mode 100644 src/cmd/8l/span.c create mode 100644 src/cmd/addr2line/addr2line_test.go delete mode 100644 src/cmd/addr2line/main.c create mode 100644 src/cmd/addr2line/main.go create mode 100644 src/cmd/gc/array.c create mode 100644 src/cmd/gc/plive.c create mode 100644 src/cmd/go/context.go create mode 100644 src/cmd/go/pkg_test.go create mode 100644 src/cmd/go/testdata/cgocover/p.go create mode 100644 src/cmd/go/testdata/cgocover/p_test.go create mode 100644 src/cmd/go/testdata/dep_test.go create mode 100644 src/cmd/go/testdata/src/notest/hello.go create mode 100644 src/cmd/go/testdata/src/testcycle/p1/p1.go create mode 100644 src/cmd/go/testdata/src/testcycle/p1/p1_test.go create mode 100644 src/cmd/go/testdata/src/testcycle/p2/p2.go create mode 100644 src/cmd/go/testdata/src/testcycle/p3/p3.go create mode 100644 src/cmd/go/testdata/src/testcycle/p3/p3_test.go create mode 100644 src/cmd/go/testdata/src/xtestonly/f.go create mode 100644 src/cmd/go/testdata/src/xtestonly/f_test.go create mode 100644 src/cmd/go/testdata/standalone_test.go create mode 100644 src/cmd/go/testdata/testonly/p_test.go create mode 100644 src/cmd/ld/pass.c create mode 100644 src/cmd/ld/pcln.c create mode 100644 src/cmd/ld/pobj.c delete mode 100644 src/cmd/nm/Makefile create mode 100644 src/cmd/nm/debug_goobj.go create mode 100644 src/cmd/nm/elf.go create mode 100644 src/cmd/nm/goobj.go create mode 100644 src/cmd/nm/macho.go delete mode 100644 src/cmd/nm/nm.c create mode 100644 src/cmd/nm/nm.go create mode 100644 src/cmd/nm/nm_test.go create mode 100644 src/cmd/nm/pe.go create mode 100644 src/cmd/nm/plan9obj.go create mode 100644 src/cmd/objdump/Makefile create mode 100644 src/cmd/objdump/armasm.go create mode 100644 src/cmd/objdump/elf.go create mode 100644 src/cmd/objdump/macho.go delete mode 100644 src/cmd/objdump/main.c create mode 100644 src/cmd/objdump/main.go create mode 100644 src/cmd/objdump/objdump_test.go create mode 100644 src/cmd/objdump/pe.go create mode 100644 src/cmd/objdump/plan9obj.go create mode 100644 src/cmd/objdump/testdata/fmthello.go create mode 100644 src/cmd/objdump/x86.go delete mode 100644 src/cmd/pack/Makefile delete mode 100644 src/cmd/pack/ar.c create mode 100644 src/cmd/pack/pack.go create mode 100644 src/cmd/pack/pack_test.go create mode 100644 src/lib9/fmt/errfmt.c delete mode 100644 src/lib9/utf/runetypebody-6.2.0.h create mode 100644 src/lib9/utf/runetypebody-6.3.0.h create mode 100644 src/liblink/Makefile create mode 100644 src/liblink/asm5.c create mode 100644 src/liblink/asm6.c create mode 100644 src/liblink/asm8.c create mode 100644 src/liblink/data.c create mode 100644 src/liblink/go.c create mode 100644 src/liblink/ld.c create mode 100644 src/liblink/list5.c create mode 100644 src/liblink/list6.c create mode 100644 src/liblink/list8.c create mode 100644 src/liblink/obj.c create mode 100644 src/liblink/obj5.c create mode 100644 src/liblink/obj6.c create mode 100644 src/liblink/obj8.c create mode 100644 src/liblink/objfile.c create mode 100644 src/liblink/pass.c create mode 100644 src/liblink/pcln.c create mode 100644 src/liblink/sym.c delete mode 100644 src/libmach/5.c delete mode 100644 src/libmach/5db.c delete mode 100644 src/libmach/5obj.c delete mode 100644 src/libmach/6.c delete mode 100644 src/libmach/6obj.c delete mode 100644 src/libmach/8.c delete mode 100644 src/libmach/8db.c delete mode 100644 src/libmach/8obj.c delete mode 100644 src/libmach/Makefile delete mode 100644 src/libmach/access.c delete mode 100644 src/libmach/darwin.c delete mode 100644 src/libmach/dragonfly.c delete mode 100644 src/libmach/elf.h delete mode 100644 src/libmach/executable.c delete mode 100644 src/libmach/fakeobj.c delete mode 100644 src/libmach/freebsd.c delete mode 100644 src/libmach/linux.c delete mode 100644 src/libmach/machdata.c delete mode 100644 src/libmach/macho.h delete mode 100644 src/libmach/map.c delete mode 100644 src/libmach/netbsd.c delete mode 100644 src/libmach/obj.c delete mode 100644 src/libmach/obj.h delete mode 100644 src/libmach/openbsd.c delete mode 100644 src/libmach/plan9.c delete mode 100644 src/libmach/setmach.c delete mode 100644 src/libmach/swap.c delete mode 100644 src/libmach/sym.c delete mode 100644 src/libmach/windows.c create mode 100755 src/nacltest.bash create mode 100644 src/pkg/archive/tar/testdata/sparse-formats.tar create mode 100644 src/pkg/archive/tar/testdata/writer-big-long.tar create mode 100644 src/pkg/archive/tar/testdata/xattrs.tar create mode 100644 src/pkg/archive/zip/testdata/zip64-2.zip create mode 100644 src/pkg/crypto/cipher/benchmark_test.go create mode 100644 src/pkg/crypto/cipher/xor.go create mode 100644 src/pkg/crypto/cipher/xor_test.go create mode 100644 src/pkg/crypto/md5/md5block_amd64p32.s create mode 100644 src/pkg/crypto/md5/md5block_generic.go create mode 100644 src/pkg/crypto/rand/util_test.go create mode 100644 src/pkg/crypto/rc4/rc4_amd64p32.s create mode 100644 src/pkg/crypto/sha1/sha1block_amd64p32.s create mode 100644 src/pkg/crypto/sha1/sha1block_arm.s create mode 100644 src/pkg/crypto/sha1/sha1block_generic.go create mode 100644 src/pkg/crypto/sha256/sha256block_386.s create mode 100644 src/pkg/crypto/sha256/sha256block_amd64.s create mode 100644 src/pkg/crypto/sha256/sha256block_decl.go create mode 100644 src/pkg/crypto/sha512/sha512block_amd64.s create mode 100644 src/pkg/crypto/sha512/sha512block_decl.go create mode 100644 src/pkg/crypto/tls/example_test.go create mode 100644 src/pkg/crypto/tls/handshake_test.go create mode 100644 src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA create mode 100644 src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA create mode 100644 src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA create mode 100644 src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA create mode 100644 src/pkg/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES create mode 100644 src/pkg/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES create mode 100644 src/pkg/crypto/tls/testdata/Client-TLSv10-RSA-RC4 create mode 100644 src/pkg/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES create mode 100644 src/pkg/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES create mode 100644 src/pkg/crypto/tls/testdata/Client-TLSv11-RSA-RC4 create mode 100644 src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA create mode 100644 src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA create mode 100644 src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA create mode 100644 src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA create mode 100644 src/pkg/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES create mode 100644 src/pkg/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM create mode 100644 src/pkg/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES create mode 100644 src/pkg/crypto/tls/testdata/Client-TLSv12-RSA-RC4 create mode 100644 src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-3DES create mode 100644 src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-AES create mode 100644 src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-RC4 create mode 100644 src/pkg/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES create mode 100644 src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-3DES create mode 100644 src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-AES create mode 100644 src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-RC4 create mode 100644 src/pkg/crypto/tls/testdata/Server-TLSv11-RSA-RC4 create mode 100644 src/pkg/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA create mode 100644 src/pkg/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA create mode 100644 src/pkg/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven create mode 100644 src/pkg/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven create mode 100644 src/pkg/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven create mode 100644 src/pkg/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES create mode 100644 src/pkg/crypto/tls/testdata/Server-TLSv12-IssueTicket create mode 100644 src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-3DES create mode 100644 src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-AES create mode 100644 src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM create mode 100644 src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-RC4 create mode 100644 src/pkg/crypto/tls/testdata/Server-TLSv12-Resume create mode 100644 src/pkg/crypto/tls/testdata/Server-TLSv12-SNI create mode 100644 src/pkg/crypto/x509/example_test.go create mode 100644 src/pkg/crypto/x509/root_cgo_darwin.go create mode 100644 src/pkg/crypto/x509/root_darwin_test.go create mode 100644 src/pkg/crypto/x509/root_nocgo_darwin.go delete mode 100644 src/pkg/crypto/x509/root_stub.go create mode 100644 src/pkg/crypto/x509/x509_test_import.go create mode 100644 src/pkg/debug/dwarf/testdata/typedef.elf4 create mode 100644 src/pkg/debug/dwarf/typeunit.go create mode 100644 src/pkg/debug/elf/testdata/go-relocation-test-clang-x86.obj create mode 100644 src/pkg/debug/elf/testdata/hello.c create mode 100644 src/pkg/debug/macho/fat.go create mode 100644 src/pkg/debug/macho/testdata/fat-gcc-386-amd64-darwin-exec create mode 100644 src/pkg/debug/pe/testdata/gcc-amd64-mingw-exec create mode 100644 src/pkg/debug/pe/testdata/gcc-amd64-mingw-obj create mode 100644 src/pkg/debug/plan9obj/file.go create mode 100644 src/pkg/debug/plan9obj/file_test.go create mode 100644 src/pkg/debug/plan9obj/plan9obj.go create mode 100755 src/pkg/debug/plan9obj/testdata/386-plan9-exec create mode 100755 src/pkg/debug/plan9obj/testdata/amd64-plan9-exec create mode 100644 src/pkg/debug/plan9obj/testdata/hello.c create mode 100644 src/pkg/encoding/json/fold.go create mode 100644 src/pkg/encoding/json/fold_test.go delete mode 100644 src/pkg/hash/crc32/crc32_amd64.go create mode 100644 src/pkg/hash/crc32/crc32_amd64p32.s create mode 100644 src/pkg/hash/crc32/crc32_amd64x.go create mode 100644 src/pkg/image/testdata/video-001.separate.dc.progression.jpeg create mode 100644 src/pkg/image/testdata/video-001.separate.dc.progression.progressive.jpeg delete mode 100644 src/pkg/io/ioutil/blackhole.go create mode 100644 src/pkg/log/example_test.go create mode 100644 src/pkg/math/abs_amd64p32.s create mode 100644 src/pkg/math/asin_amd64p32.s create mode 100644 src/pkg/math/atan2_amd64p32.s create mode 100644 src/pkg/math/atan_amd64p32.s create mode 100644 src/pkg/math/big/arith_amd64p32.s create mode 100644 src/pkg/math/dim_amd64p32.s create mode 100644 src/pkg/math/exp2_amd64p32.s create mode 100644 src/pkg/math/exp_amd64p32.s create mode 100644 src/pkg/math/expm1_amd64p32.s create mode 100644 src/pkg/math/floor_amd64p32.s create mode 100644 src/pkg/math/frexp_amd64p32.s create mode 100644 src/pkg/math/hypot_amd64p32.s create mode 100644 src/pkg/math/ldexp_amd64p32.s create mode 100644 src/pkg/math/log10_amd64p32.s create mode 100644 src/pkg/math/log1p_amd64p32.s create mode 100644 src/pkg/math/log_amd64p32.s create mode 100644 src/pkg/math/mod_amd64p32.s create mode 100644 src/pkg/math/modf_amd64p32.s create mode 100644 src/pkg/math/rand/regress_test.go create mode 100644 src/pkg/math/remainder_amd64p32.s create mode 100644 src/pkg/math/sin_amd64p32.s create mode 100644 src/pkg/math/sincos_amd64p32.s create mode 100644 src/pkg/math/sqrt_amd64p32.s create mode 100644 src/pkg/math/tan_amd64p32.s create mode 100644 src/pkg/mime/multipart/example_test.go create mode 100644 src/pkg/net/cgo_unix_test.go create mode 100644 src/pkg/net/dnsclient_test.go create mode 100644 src/pkg/net/dnsconfig_unix_test.go create mode 100644 src/pkg/net/fd_poll_nacl.go create mode 100644 src/pkg/net/http/httputil/httputil.go create mode 100644 src/pkg/net/http/race.go create mode 100644 src/pkg/net/netgo_unix_test.go create mode 100644 src/pkg/net/rpc/client_test.go create mode 100644 src/pkg/net/smtp/example_test.go create mode 100644 src/pkg/net/sock_solaris.go create mode 100644 src/pkg/net/sockopt_plan9.go create mode 100644 src/pkg/net/sockopt_solaris.go create mode 100644 src/pkg/net/sockoptip_stub.go create mode 100644 src/pkg/net/tcpsockopt_dragonfly.go create mode 100644 src/pkg/net/tcpsockopt_plan9.go create mode 100644 src/pkg/net/tcpsockopt_solaris.go create mode 100644 src/pkg/net/testdata/resolv.conf create mode 100644 src/pkg/net/z_last_test.go create mode 100644 src/pkg/os/stat_nacl.go create mode 100644 src/pkg/os/stat_solaris.go create mode 100644 src/pkg/os/sys_darwin.go create mode 100644 src/pkg/os/sys_freebsd.go create mode 100644 src/pkg/os/sys_nacl.go create mode 100644 src/pkg/os/sys_solaris.go create mode 100644 src/pkg/os/sys_unix.go create mode 100644 src/pkg/path/filepath/export_test.go create mode 100644 src/pkg/reflect/asm_amd64p32.s create mode 100644 src/pkg/regexp/onepass.go create mode 100644 src/pkg/regexp/onepass_test.go delete mode 100644 src/pkg/runtime/alg.c create mode 100644 src/pkg/runtime/alg.goc create mode 100644 src/pkg/runtime/arch_amd64p32.h create mode 100644 src/pkg/runtime/asm_amd64p32.s delete mode 100644 src/pkg/runtime/atomic_amd64.c create mode 100644 src/pkg/runtime/atomic_amd64x.c create mode 100644 src/pkg/runtime/cgo/asm_nacl_amd64p32.s delete mode 100644 src/pkg/runtime/chan.c create mode 100644 src/pkg/runtime/chan.goc create mode 100644 src/pkg/runtime/chan.h delete mode 100644 src/pkg/runtime/complex.c create mode 100644 src/pkg/runtime/complex.goc delete mode 100644 src/pkg/runtime/cpuprof.c create mode 100644 src/pkg/runtime/cpuprof.goc create mode 100644 src/pkg/runtime/debug/heapdump_test.go create mode 100644 src/pkg/runtime/defs.c create mode 100644 src/pkg/runtime/defs_nacl_386.h create mode 100644 src/pkg/runtime/defs_nacl_amd64p32.h create mode 100644 src/pkg/runtime/defs_solaris.go create mode 100644 src/pkg/runtime/defs_solaris_amd64.go create mode 100644 src/pkg/runtime/defs_solaris_amd64.h delete mode 100644 src/pkg/runtime/export_test.c delete mode 100644 src/pkg/runtime/hashmap.c create mode 100644 src/pkg/runtime/hashmap.goc create mode 100644 src/pkg/runtime/hashmap.h create mode 100644 src/pkg/runtime/heapdump.c delete mode 100644 src/pkg/runtime/iface.c create mode 100644 src/pkg/runtime/iface.goc delete mode 100644 src/pkg/runtime/lfstack.c create mode 100644 src/pkg/runtime/lfstack.goc create mode 100644 src/pkg/runtime/mem_nacl.c create mode 100644 src/pkg/runtime/mem_solaris.c create mode 100644 src/pkg/runtime/memclr_386.s create mode 100644 src/pkg/runtime/memclr_amd64.s create mode 100644 src/pkg/runtime/memclr_plan9_386.s create mode 100644 src/pkg/runtime/memclr_plan9_amd64.s create mode 100644 src/pkg/runtime/memmove_nacl_amd64p32.s create mode 100644 src/pkg/runtime/memmove_plan9_386.s create mode 100644 src/pkg/runtime/memmove_plan9_amd64.s delete mode 100644 src/pkg/runtime/mfinal.c create mode 100644 src/pkg/runtime/mknacl.sh create mode 100644 src/pkg/runtime/netpoll_nacl.c create mode 100644 src/pkg/runtime/netpoll_solaris.c create mode 100644 src/pkg/runtime/os_nacl.c create mode 100644 src/pkg/runtime/os_nacl.h create mode 100644 src/pkg/runtime/os_solaris.c create mode 100644 src/pkg/runtime/os_solaris.h delete mode 100644 src/pkg/runtime/proc.p create mode 100644 src/pkg/runtime/rdebug.goc create mode 100644 src/pkg/runtime/rt0_nacl_386.s create mode 100644 src/pkg/runtime/rt0_nacl_amd64p32.s create mode 100644 src/pkg/runtime/rt0_solaris_amd64.s create mode 100644 src/pkg/runtime/runtime_unix_test.go delete mode 100644 src/pkg/runtime/signal_amd64.c create mode 100644 src/pkg/runtime/signal_amd64x.c create mode 100644 src/pkg/runtime/signal_nacl_386.h create mode 100644 src/pkg/runtime/signal_nacl_amd64p32.h create mode 100644 src/pkg/runtime/signal_solaris_amd64.h create mode 100644 src/pkg/runtime/signals_nacl.h create mode 100644 src/pkg/runtime/signals_solaris.h delete mode 100644 src/pkg/runtime/slice.c create mode 100644 src/pkg/runtime/slice.goc create mode 100644 src/pkg/runtime/sqrt.go create mode 100644 src/pkg/runtime/stack_gen_test.go delete mode 100644 src/pkg/runtime/symtab.c create mode 100644 src/pkg/runtime/symtab.goc create mode 100644 src/pkg/runtime/sys_nacl_386.s create mode 100644 src/pkg/runtime/sys_nacl_amd64p32.s create mode 100644 src/pkg/runtime/sys_solaris_amd64.s create mode 100644 src/pkg/runtime/syscall_nacl.h create mode 100644 src/pkg/runtime/syscall_solaris.goc create mode 100644 src/pkg/strconv/quote_example_test.go create mode 100644 src/pkg/sync/atomic/asm_amd64p32.s create mode 100644 src/pkg/sync/pool.go create mode 100644 src/pkg/sync/pool_test.go create mode 100644 src/pkg/syscall/asm_nacl_386.s create mode 100644 src/pkg/syscall/asm_nacl_amd64p32.s create mode 100644 src/pkg/syscall/asm_solaris_amd64.s delete mode 100644 src/pkg/syscall/consistency_unix_test.go create mode 100644 src/pkg/syscall/exec_solaris.go create mode 100644 src/pkg/syscall/fd_nacl.go create mode 100644 src/pkg/syscall/flock.go create mode 100644 src/pkg/syscall/flock_linux_32bit.go create mode 100644 src/pkg/syscall/fs_nacl.go create mode 100644 src/pkg/syscall/mkall_windows.bat delete mode 100755 src/pkg/syscall/mkerrors_windows.sh create mode 100755 src/pkg/syscall/mksyscall_solaris.pl create mode 100644 src/pkg/syscall/mksyscall_windows.go delete mode 100755 src/pkg/syscall/mksyscall_windows.pl create mode 100644 src/pkg/syscall/mmap_unix_test.go create mode 100644 src/pkg/syscall/net_nacl.go delete mode 100644 src/pkg/syscall/passfd_test.go delete mode 100644 src/pkg/syscall/rlimit_linux_test.go create mode 100644 src/pkg/syscall/route_freebsd_32bit.go create mode 100644 src/pkg/syscall/route_freebsd_64bit.go create mode 100644 src/pkg/syscall/so_solaris.go create mode 100644 src/pkg/syscall/srpc_nacl.go create mode 100644 src/pkg/syscall/syscall_bsd_test.go create mode 100644 src/pkg/syscall/syscall_nacl.go create mode 100644 src/pkg/syscall/syscall_nacl_386.go create mode 100644 src/pkg/syscall/syscall_nacl_amd64p32.go create mode 100644 src/pkg/syscall/syscall_solaris.go create mode 100644 src/pkg/syscall/syscall_solaris_amd64.go create mode 100644 src/pkg/syscall/syscall_unix_test.go create mode 100644 src/pkg/syscall/tables_nacl.go create mode 100644 src/pkg/syscall/time_nacl_386.s create mode 100644 src/pkg/syscall/time_nacl_amd64p32.s create mode 100644 src/pkg/syscall/types_solaris.go create mode 100644 src/pkg/syscall/unzip_nacl.go create mode 100644 src/pkg/syscall/zerrors_solaris_amd64.go create mode 100644 src/pkg/syscall/zsyscall_nacl_386.go create mode 100644 src/pkg/syscall/zsyscall_nacl_amd64p32.go create mode 100644 src/pkg/syscall/zsyscall_solaris_amd64.go create mode 100644 src/pkg/syscall/zsysnum_solaris_amd64.go create mode 100644 src/pkg/syscall/ztypes_solaris_amd64.go create mode 100644 src/pkg/time/format_test.go create mode 100644 src/pkg/time/zoneinfo_test.go delete mode 100644 test/fixedbugs/bug191.out create mode 100644 test/fixedbugs/bug480.dir/a.go create mode 100644 test/fixedbugs/bug480.dir/b.go create mode 100644 test/fixedbugs/bug480.go create mode 100644 test/fixedbugs/bug481.go create mode 100644 test/fixedbugs/bug482.go create mode 100644 test/fixedbugs/bug483.go create mode 100644 test/fixedbugs/bug484.go create mode 100644 test/fixedbugs/bug485.go create mode 100644 test/fixedbugs/issue1304.go create mode 100644 test/fixedbugs/issue4388.go create mode 100644 test/fixedbugs/issue5793.go create mode 100644 test/fixedbugs/issue6295.dir/p0.go create mode 100644 test/fixedbugs/issue6295.dir/p1.go create mode 100644 test/fixedbugs/issue6295.dir/p2.go create mode 100644 test/fixedbugs/issue6295.go create mode 100644 test/fixedbugs/issue6402.go create mode 100644 test/fixedbugs/issue6403.go create mode 100644 test/fixedbugs/issue6405.go create mode 100644 test/fixedbugs/issue6406.go create mode 100644 test/fixedbugs/issue6500.go create mode 100644 test/fixedbugs/issue6572.go create mode 100644 test/fixedbugs/issue6789.dir/a.go create mode 100644 test/fixedbugs/issue6789.dir/b.go create mode 100644 test/fixedbugs/issue6789.go create mode 100644 test/fixedbugs/issue6847.go create mode 100644 test/fixedbugs/issue6889.go create mode 100644 test/fixedbugs/issue6899.go create mode 100644 test/fixedbugs/issue6899.out create mode 100644 test/fixedbugs/issue6902.go create mode 100644 test/fixedbugs/issue6964.go create mode 100644 test/fixedbugs/issue7023.dir/a.go create mode 100644 test/fixedbugs/issue7023.dir/b.go create mode 100644 test/fixedbugs/issue7023.go create mode 100644 test/fixedbugs/issue7044.go create mode 100644 test/fixedbugs/issue7050.go create mode 100644 test/fixedbugs/issue7083.go create mode 100644 test/fixedbugs/issue7129.go create mode 100644 test/fixedbugs/issue7150.go create mode 100644 test/fixedbugs/issue7153.go create mode 100644 test/fixedbugs/issue7214.go create mode 100644 test/fixedbugs/issue7223.go create mode 100644 test/fixedbugs/issue7272.go create mode 100644 test/fixedbugs/issue7310.go create mode 100644 test/fixedbugs/issue7316.go create mode 100644 test/fixedbugs/issue7346.go create mode 100644 test/fixedbugs/issue7366.go create mode 100644 test/fixedbugs/issue7405.go create mode 100644 test/fixedbugs/issue7419.go create mode 100644 test/fixedbugs/issue7525.go create mode 100644 test/fixedbugs/issue7538a.go create mode 100644 test/fixedbugs/issue7538b.go create mode 100644 test/fixedbugs/issue7547.go create mode 100644 test/fixedbugs/issue7550.go create mode 100644 test/fixedbugs/issue7590.go create mode 100644 test/fixedbugs/issue7648.dir/a.go create mode 100644 test/fixedbugs/issue7648.dir/b.go create mode 100644 test/fixedbugs/issue7648.go create mode 100644 test/fixedbugs/issue7675.go create mode 100644 test/fixedbugs/issue7742.go create mode 100644 test/fixedbugs/issue7794.go create mode 100644 test/fixedbugs/issue7863.go create mode 100644 test/fixedbugs/issue7867.go create mode 100644 test/fixedbugs/issue7884.go create mode 100644 test/fixedbugs/issue7944.go create mode 100644 test/fixedbugs/issue7995.go create mode 100644 test/fixedbugs/issue7995b.dir/x1.go create mode 100644 test/fixedbugs/issue7995b.dir/x2.go create mode 100644 test/fixedbugs/issue7995b.go create mode 100644 test/fixedbugs/issue7996.go create mode 100644 test/fixedbugs/issue7997.go create mode 100644 test/fixedbugs/issue7998.go create mode 100644 test/fixedbugs/issue8004.go create mode 100644 test/fixedbugs/issue8011.go create mode 100644 test/fixedbugs/issue8028.go create mode 100644 test/fixedbugs/issue8036.go create mode 100644 test/fixedbugs/issue8039.go create mode 100644 test/fixedbugs/issue8047.go create mode 100644 test/fixedbugs/issue8047b.go create mode 100644 test/fixedbugs/issue8048.go create mode 100644 test/fixedbugs/issue8073.go create mode 100644 test/fixedbugs/issue8076.go create mode 100644 test/fixedbugs/issue8132.go create mode 100644 test/fixedbugs/issue8139.go create mode 100644 test/fixedbugs/issue8155.go create mode 100644 test/fixedbugs/issue8158.go create mode 100644 test/float_lit2.go create mode 100644 test/float_lit3.go create mode 100644 test/gcstring.go create mode 100644 test/live.go create mode 100644 test/live1.go create mode 100644 test/live2.go create mode 100644 test/nilptr4.go create mode 100644 test/nosplit.go create mode 100644 test/tinyfin.go diff --git a/AUTHORS b/AUTHORS index c3fd330e8..d4fbbd143 100644 --- a/AUTHORS +++ b/AUTHORS @@ -12,6 +12,7 @@ Aaron France Abhinav Gupta Adrian Nos Adrian O'Grady +Adrien Bustany Akshat Kumar Albert Strasheim Alberto García Hierro @@ -19,12 +20,15 @@ Aleksandar Dezelin Alex A Skinner Alex Brainman Alex Jin +Alexander Larsson Alexander Orlov Alexander Reece Alexander Surma +Alexander Zhavnerchik Alexandre Normand Alexei Sholik Alexey Borzenkov +Alexey Palazhchenko Amir Mohammad Saied Amrut Joshi Andrei Vieru @@ -35,16 +39,21 @@ Andrew Lutomirski Andrew Pritchard Andrew Radev Andrew Skiba +Andrew Szeto Andrew Wilkins Andrey Mirtchovski Andriy Lytvynov Andy Davis +Anfernee Yongkun Gui Anh Hai Trinh Anschel Schaffer-Cohen Anthony Eufemio Anthony Martin Anthony Starks +Apisak Darakananda +Aram Hăvărneanu Arnaud Ysmal +Arne Hormann Aron Nopanen Arvindh Rajesh Tamilmani Ato Araki @@ -53,18 +62,23 @@ Ben Olive Benjamin Black Benny Siegert Berengar Lehr +Billie Harold Cleek Bjorn Tillenius Bjorn Tipling Blake Mizerany Bobby Powers +Brendan Daniel Tracey Brian Dellisanti Brian G. Merrell Brian Gitonga Marete Brian Ketelsen Caine Tighe Caleb Spare +Carl Chatfield Carlos Castillo +Case Nelson Casey Marshall +Cezar Sá Espinola ChaiShushan Charles L. Dorian Charles Lee @@ -75,6 +89,7 @@ Chris Jones Chris Lennert Christian Himpel Christine Hansmann +Christoffer Buchholz Christoph Hack Christopher Cahoon Christopher Nielsen @@ -89,19 +104,25 @@ Dan Peterson Dan Sinclair Daniel Fleischman Daniel Krech +Daniel Lidén Daniel Morsing Daniel Theophanes Darren Elwood Dave Cheney David Bürgin <676c7473@gmail.com> +David Calavera David du Colombier <0intro@gmail.com> David Forsythe David G. Andersen David Jakob Fritz +David Thomas David Titarenco Dean Prichard +Denis Brandolini Devon H. O'Dell +Dhiru Kholia Dimitri Tcaciuc +Dmitri Shuralyov Dmitriy Shelenin Dmitry Chestnykh Dominik Honnef @@ -121,36 +142,46 @@ Eric Clark Eric Milliken Eric Roshan-Eisner Erik St. Martin +Erik Westrup Esko Luontola Evan Shaw Ewan Chou +Fabrizio Milo Fan Hongjian Fazlul Shahriar +Felix Geisendörfer Firmansyah Adiputra Florian Uekermann Florian Weimer Francisco Souza Frederick Kelly Mayle III +Fredrik Enestad Frithjof Schulze Gary Burd +Gautham Thambidorai Georg Reinke Gerasimos Dimitriadis Gideon Jan-Wessel Redelinghuys Giles Lean Google Inc. +Gordon Klaus +Graham King Graham Miller Greg Ward +Guillaume J. Charmes Gustav Paul Gustavo Niemeyer Gwenael Treguier Harley Laue Hector Chu +Henrik Edwards Herbert Georg Fischer Hong Ruiqi Icarus Sparry Ingo Oeser Isaac Wagner Jakob Borg +Jakub Ryszard Czarnowicz James David Chalfant James Fysh James Gray @@ -165,7 +196,9 @@ Jan Newmarch Jan Ziak <0xe2.0x9a.0x9b@gmail.com> Jani Monoses Jaroslavas Počepko +Jason Del Ponte Jason Travis +Jay Weisskopf Jeff Hodges Jeff R. Allen Jeff Sickel @@ -177,6 +210,7 @@ Jingcheng Zhang Joakim Sernbrant Joe Poirier John Asmuth +John C Barstow John Graham-Cumming John Howard Palevich John Shahid @@ -190,6 +224,7 @@ Joseph Holsten Josh Bleecher Snyder Josh Goebel Josh Holland +Joshua Chase Jukka-Pekka Kekkonen Julian Phillips Julien Schmidt @@ -198,55 +233,75 @@ Kamil Kisiel Katrina Owen Kei Son Keith Rarick +Kelsey Hightower +Kelvin Foo Chuan Lyi Ken Friedenbach Ken Rockot Kevin Ballard Kyle Consalus +Kyle Isom Kyle Lemons L Campbell Lai Jiangshan +Linaro Limited Lorenzo Stoakes Luca Greco Lucio De Re Luit van Drongelen +Luka Zakrajšek +Luke Curley +Marc Weistroff Marco Hennings Marko Juhani Silokunnas +Marko Tiikkaja Markus Duft Markus Sonderegger +Markus Zimmermann Martin Neubauer +Martin Olsson Mateusz Czapliński Mathieu Lonjaret Mats Lidell +Matt Aimonetti Matt Jibson Matt Joiner Matt Reiferson Matthew Cottingham Matthew Horsnell +Maxim Khitrov Micah Stetson Michael Chaten Michael Elkins -Michael Gehring +Michael Fraenkel +Michael Gehring Michael Hoisie Michael Lewis +Michael Pearson Michael Stapelberg Michael Teichgräber Michał Derkacz Miek Gieben +Mihai Borobocea Mikael Tillenius +Mike Andrews Mike Rosset +Mikhail Panchenko Miki Tebeka Mikio Hara Mikkel Krautz Miquel Sabaté Solà +Moov Corporation Moriyoshi Koizumi Môshe van der Sterre Nan Deng Nathan John Youngman ngmoco, LLC +Nicholas Katsaros Nicholas Presta Nicholas Sullivan Nicholas Waples Nick Craig-Wood +Nicolas Kaiser Nicolas Owens Nigel Kerr Noah Campbell @@ -261,24 +316,32 @@ Pascal S. de Kloe Patrick Crosby Patrick Gavlin Patrick Higgins +Patrick Mézard Patrick Mylund Nielsen Patrick Smith +Paul A Querna +Paul Hammond Paul Lalonde Paul Sbarra Paul van Brouwershaven +Pavel Zinovkin Petar Maymounkov Peter Armitage Peter Froehlich Peter Kleiweg Peter Mundy Péter Surányi +Péter Szilágyi Peter Waller Peter Williams Philip K. Warren Pieter Droogendijk +Pietro Gagliardi +Preetam Jinka Quan Yong Zhai Raif S. Naffah Rémy Oudompheng +Richard Crowley Richard Eric Gavaletz Richard Musiol Rick Arnold @@ -295,8 +358,10 @@ Roger Pau Monné Roger Peppe Ron Minnich Ross Light +Rowan Worth Ryan Hitchman Ryan Slade +S.Çağlar Onur Sanjay Menakuru Scott Ferguson Scott Lawrence @@ -311,12 +376,14 @@ Shenghou Ma Shivakumar GN Sokolov Yura Spring Mc +StalkR Stefan Nilsson Stéphane Travostino Stephen McQuay Stephen Weinberg Steve McCoy Steven Elliot Harris +Steven Hartland Sven Almgren Szabolcs Nagy Tad Glines @@ -328,6 +395,8 @@ Thomas Kappler Timo Savola Tobias Columbus Tor Andersson +Travis Cline +Tudor Golubenco Tw Tyler Bunnell Ugorji Nwoke @@ -342,6 +411,7 @@ Volker Dobler Wei Guangjing Willem van der Schyff William Josephson +William Orr Xing Xing Yasuhiro Matsumoto Yissakhar Z. Beck @@ -352,3 +422,4 @@ Yuusei Kuwana Yuval Pavel Zholkover Ziad Hatahet Zorion Arrizabalaga +申习之 diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 4d4a73e72..372229848 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -37,6 +37,7 @@ Abhinav Gupta Adam Langley Adrian Nos Adrian O'Grady +Adrien Bustany Akshat Kumar Alan Donovan Albert Strasheim @@ -46,13 +47,16 @@ Alex A Skinner Alex Brainman Alex Bramley Alex Jin +Alexander Larsson Alexander Orlov Alexander Reece Alexander Surma +Alexander Zhavnerchik Alexandre Normand Alexandru Moșoi Alexei Sholik Alexey Borzenkov +Alexey Palazhchenko Alexis Imperial-Legrand Amir Mohammad Saied Amrut Joshi @@ -67,16 +71,21 @@ Andrew Lutomirski Andrew Pritchard Andrew Radev Andrew Skiba +Andrew Szeto Andrew Wilkins Andrey Mirtchovski Andriy Lytvynov Andy Davis +Anfernee Yongkun Gui Anh Hai Trinh Anschel Schaffer-Cohen Anthony Eufemio Anthony Martin Anthony Starks +Apisak Darakananda +Aram Hăvărneanu Arnaud Ysmal +Arne Hormann Aron Nopanen Arvindh Rajesh Tamilmani Asim Shankar @@ -93,25 +102,32 @@ Benny Siegert Berengar Lehr Bill Neubauer Bill Thiede +Billie Harold Cleek Bjorn Tillenius Bjorn Tipling Blake Mizerany Bobby Powers Brad Fitzpatrick Brad Garcia +Brendan Daniel Tracey Brendan O'Dea Brian Dellisanti Brian G. Merrell Brian Gitonga Marete Brian Ketelsen Brian Slesinsky +Burcu Dogan Caine Tighe Caleb Spare +Carl Chatfield Carl Mastrangelo Carl Shapiro Carlos Castillo Cary Hull +Case Nelson Casey Marshall +Catalin Patulea +Cezar Sá Espinola ChaiShushan Charles L. Dorian Charles Lee @@ -124,6 +140,7 @@ Chris Lennert Chris Manghane Christian Himpel Christine Hansmann +Christoffer Buchholz Christoph Hack Christopher Cahoon Christopher Nielsen @@ -141,6 +158,7 @@ Dan Peterson Dan Sinclair Daniel Fleischman Daniel Krech +Daniel Lidén Daniel Morsing Daniel Nadasi Daniel Theophanes @@ -150,8 +168,11 @@ Dave Cheney Dave Day Dave Grijalva David Anderson +David Barnett David Bürgin <676c7473@gmail.com> -David Crawshaw +David Calavera +David Covert +David Crawshaw David du Colombier <0intro@gmail.com> David Forsythe David G. Andersen @@ -159,10 +180,14 @@ David Jakob Fritz David McLeish David Presotto David Symonds +David Thomas David Titarenco Dean Prichard +Denis Brandolini Devon H. O'Dell +Dhiru Kholia Dimitri Tcaciuc +Dmitri Shuralyov Dmitriy Shelenin Dmitriy Vyukov Dmitry Chestnykh @@ -183,12 +208,15 @@ Eric Clark Eric Milliken Eric Roshan-Eisner Erik St. Martin +Erik Westrup Esko Luontola Evan Martin Evan Shaw Ewan Chou +Fabrizio Milo Fan Hongjian Fazlul Shahriar +Felix Geisendörfer Firmansyah Adiputra Florian Uekermann Florian Weimer @@ -196,16 +224,21 @@ Folke Behrens Francesc Campoy Francisco Souza Frederick Kelly Mayle III +Fredrik Enestad Frithjof Schulze Fumitoshi Ukai Gaal Yahas Gary Burd +Gautham Thambidorai Georg Reinke Gerasimos Dimitriadis Gideon Jan-Wessel Redelinghuys Giles Lean +Gordon Klaus +Graham King Graham Miller Greg Ward +Guillaume J. Charmes Gustav Paul Gustavo Franco Gustavo Niemeyer @@ -213,6 +246,7 @@ Gwenael Treguier Han-Wen Nienhuys Harley Laue Hector Chu +Henrik Edwards Herbert Georg Fischer Hong Ruiqi Hossein Sheikh Attar @@ -223,6 +257,7 @@ Isaac Wagner Ivan Krasin Jacob Baskin Jakob Borg +Jakub Ryszard Czarnowicz James Aguilar James David Chalfant James Fysh @@ -242,7 +277,9 @@ Jan Newmarch Jan Ziak <0xe2.0x9a.0x9b@gmail.com> Jani Monoses Jaroslavas Počepko +Jason Del Ponte Jason Travis +Jay Weisskopf Jean-Marc Eurin Jeff Hodges Jeff R. Allen @@ -260,9 +297,11 @@ Joel Sing Johan Euphrosine John Asmuth John Beisley +John C Barstow John DeNero John Graham-Cumming John Howard Palevich +John Newlin John Shahid Jonathan Allie Jonathan Feinberg @@ -282,6 +321,7 @@ Josh Bleecher Snyder Josh Goebel Josh Hoak Josh Holland +Joshua Chase JP Sugarbroad Jukka-Pekka Kekkonen Julian Phillips @@ -289,9 +329,12 @@ Julien Schmidt Kai Backman Kamil Kisiel Katrina Owen +Kay Zhu Kei Son Keith Randall Keith Rarick +Kelsey Hightower +Kelvin Foo Chuan Lyi Ken Friedenbach Ken Rockot Ken Thompson @@ -299,6 +342,7 @@ Kevin Ballard Kevin Klues Kirklin McDonald Kyle Consalus +Kyle Isom Kyle Lemons L Campbell Lai Jiangshan @@ -308,19 +352,27 @@ Louis Kruger Luca Greco Lucio De Re Luit van Drongelen +Luka Zakrajšek +Luke Curley Luuk van Dijk +Manoj Dayaram Manu Garg +Marc Weistroff Marcel van Lohuizen Marco Hennings Mark Zavislak Marko Juhani Silokunnas Marko Mikulicic +Marko Tiikkaja Markus Duft Markus Sonderegger +Markus Zimmermann Martin Neubauer +Martin Olsson Mateusz Czapliński Mathieu Lonjaret Mats Lidell +Matt Aimonetti Matt Brown Matt Jibson Matt Joiner @@ -329,15 +381,20 @@ Matt Reiferson Matthew Cottingham Matthew Dempsky Matthew Horsnell +Maxim Khitrov Maxim Pimenov Maxim Ushakov Micah Stetson Michael Chaten Michael Elkins -Michael Gehring +Michael Fraenkel +Michael Gehring Michael Hoisie +Michael Hudson-Doyle +Michael Kelly Michael Lewis Michael Matloob +Michael Pearson Michael Piatek Michael Shields Michael Stapelberg @@ -345,10 +402,13 @@ Michael T. Jones Michael Teichgräber Michał Derkacz Miek Gieben +Mihai Borobocea Mikael Tillenius +Mike Andrews Mike Rosset Mike Samuel Mike Solomon +Mikhail Panchenko Miki Tebeka Mikio Hara Mikkel Krautz @@ -357,10 +417,12 @@ Moriyoshi Koizumi Môshe van der Sterre Nan Deng Nathan John Youngman +Nicholas Katsaros Nicholas Presta Nicholas Sullivan Nicholas Waples Nick Craig-Wood +Nicolas Kaiser Nicolas Owens Nigel Kerr Nigel Tao @@ -376,32 +438,42 @@ Pascal S. de Kloe Patrick Crosby Patrick Gavlin Patrick Higgins +Patrick Mézard Patrick Mylund Nielsen +Patrick Riley Patrick Smith +Paul A Querna Paul Borman Paul Chang +Paul Hammond Paul Lalonde Paul Sbarra Paul van Brouwershaven +Pavel Zinovkin Pawel Szczur Petar Maymounkov Peter Armitage +Peter Collingbourne Peter Froehlich Peter Kleiweg Peter McKenzie Peter Mundy Péter Surányi Péter Szabó +Péter Szilágyi Peter Waller Peter Weinberger Peter Williams Phil Pennock Philip K. Warren Pieter Droogendijk +Pietro Gagliardi +Preetam Jinka Quan Yong Zhai Raif S. Naffah Raph Levien Rémy Oudompheng +Richard Crowley Richard Eric Gavaletz Richard Musiol Rick Arnold @@ -413,6 +485,7 @@ Robert Figueiredo Robert Griesemer Robert Hencke Robert Obryk +Robert Sesek Robert Snedegar Robin Eklind Rodrigo Moraes de Oliveira @@ -421,16 +494,20 @@ Roger Pau Monné Roger Peppe Ron Minnich Ross Light +Rowan Worth +Rui Ueyama Russ Cox Ryan Barrett Ryan Hitchman Ryan Slade +S.Çağlar Onur Sam Thorogood Sameer Ajmani Sanjay Menakuru Scott Ferguson Scott Lawrence Scott Schwartz +Sean Burford Sebastien Binet Sébastien Paolacci Sergei Skorobogatov @@ -439,10 +516,11 @@ Sergio Luis O. B. Correia Shane Hansen Shawn Ledbetter Shawn Smith -Shenghou Ma +Shenghou Ma Shivakumar GN Sokolov Yura Spring Mc +StalkR Stefan Nilsson Stéphane Travostino Stephen Ma @@ -450,6 +528,7 @@ Stephen McQuay Stephen Weinberg Steve McCoy Steven Elliot Harris +Steven Hartland Sugu Sougoumarane Sven Almgren Szabolcs Nagy @@ -465,7 +544,9 @@ Tobias Columbus Todd Wang Tom Szymanski Tor Andersson +Travis Cline Trevor Strohman +Tudor Golubenco Tw Tyler Bunnell Ugorji Nwoke @@ -484,7 +565,9 @@ Will Norris Willem van der Schyff William Chan William Josephson +William Orr Xing Xing +Yan Zou Yasuhiro Matsumoto Yissakhar Z. Beck Yongjian Xu @@ -495,3 +578,4 @@ Yuval Pavel Zholkover Yves Junqueira Ziad Hatahet Zorion Arrizabalaga +申习之 diff --git a/VERSION b/VERSION index 39dbf6463..9c3a7a187 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -go1.2.1 \ No newline at end of file +go1.3 \ No newline at end of file diff --git a/api/except.txt b/api/except.txt index 92a52789d..1a8296635 100644 --- a/api/except.txt +++ b/api/except.txt @@ -5,6 +5,10 @@ pkg syscall (darwin-amd64), func Fchflags(string, int) error pkg syscall (darwin-amd64-cgo), func Fchflags(string, int) error pkg syscall (freebsd-386), func Fchflags(string, int) error pkg syscall (freebsd-amd64), func Fchflags(string, int) error +pkg syscall (freebsd-arm), func Fchflags(string, int) error +pkg syscall (freebsd-arm-cgo), func Fchflags(string, int) error +pkg syscall (netbsd-arm), func Fchflags(string, int) error +pkg syscall (netbsd-arm-cgo), func Fchflags(string, int) error pkg testing, func RegisterCover(Cover) pkg text/template/parse, type DotNode bool pkg text/template/parse, type Node interface { Copy, String, Type } @@ -14,3 +18,312 @@ pkg syscall (darwin-386), const ImplementsGetwd = false pkg syscall (darwin-386-cgo), const ImplementsGetwd = false pkg syscall (darwin-amd64), const ImplementsGetwd = false pkg syscall (darwin-amd64-cgo), const ImplementsGetwd = false +pkg syscall (openbsd-386), const BIOCGRTIMEOUT = 1074283118 +pkg syscall (openbsd-386), const BIOCSRTIMEOUT = 2148024941 +pkg syscall (openbsd-386), const RTF_FMASK = 63496 +pkg syscall (openbsd-386), const RTM_VERSION = 4 +pkg syscall (openbsd-386), const SIOCBRDGDADDR = 2150132039 +pkg syscall (openbsd-386), const SIOCBRDGGPARAM = 3224922456 +pkg syscall (openbsd-386), const SIOCBRDGSADDR = 3223873860 +pkg syscall (openbsd-386), const SYS_CLOCK_GETRES = 234 +pkg syscall (openbsd-386), const SYS_CLOCK_GETTIME = 232 +pkg syscall (openbsd-386), const SYS_CLOCK_SETTIME = 233 +pkg syscall (openbsd-386), const SYS_FHSTATFS = 309 +pkg syscall (openbsd-386), const SYS_FSTAT = 292 +pkg syscall (openbsd-386), const SYS_FSTATAT = 316 +pkg syscall (openbsd-386), const SYS_FSTATFS = 308 +pkg syscall (openbsd-386), const SYS_FUTIMENS = 327 +pkg syscall (openbsd-386), const SYS_FUTIMES = 206 +pkg syscall (openbsd-386), const SYS_GETDIRENTRIES = 312 +pkg syscall (openbsd-386), const SYS_GETDIRENTRIES ideal-int +pkg syscall (openbsd-386), const SYS_GETFSSTAT = 306 +pkg syscall (openbsd-386), const SYS_GETITIMER = 86 +pkg syscall (openbsd-386), const SYS_GETRUSAGE = 117 +pkg syscall (openbsd-386), const SYS_GETTIMEOFDAY = 116 +pkg syscall (openbsd-386), const SYS_KEVENT = 270 +pkg syscall (openbsd-386), const SYS_LSTAT = 293 +pkg syscall (openbsd-386), const SYS_NANOSLEEP = 240 +pkg syscall (openbsd-386), const SYS_SELECT = 93 +pkg syscall (openbsd-386), const SYS_SETITIMER = 83 +pkg syscall (openbsd-386), const SYS_SETTIMEOFDAY = 122 +pkg syscall (openbsd-386), const SYS_STAT = 291 +pkg syscall (openbsd-386), const SYS_STATFS = 307 +pkg syscall (openbsd-386), const SYS_UTIMENSAT = 326 +pkg syscall (openbsd-386), const SYS_UTIMES = 138 +pkg syscall (openbsd-386), const SYS_WAIT4 = 7 +pkg syscall (openbsd-386), const SYS___THRSLEEP = 300 +pkg syscall (openbsd-386), const SizeofIfData = 208 +pkg syscall (openbsd-386), const SizeofIfMsghdr = 232 +pkg syscall (openbsd-386), const SizeofRtMetrics = 48 +pkg syscall (openbsd-386), const SizeofRtMsghdr = 88 +pkg syscall (openbsd-386), const TIOCGTSTAMP = 1074295899 +pkg syscall (openbsd-386), type Dirent struct, Fileno uint32 +pkg syscall (openbsd-386), type FdSet struct, Bits [32]int32 +pkg syscall (openbsd-386), type Kevent_t struct, Data int32 +pkg syscall (openbsd-386), type Mclpool struct, Grown uint32 +pkg syscall (openbsd-386), type RtMetrics struct, Expire uint32 +pkg syscall (openbsd-386), type Stat_t struct, Ino uint32 +pkg syscall (openbsd-386), type Stat_t struct, Lspare0 int32 +pkg syscall (openbsd-386), type Stat_t struct, Lspare1 int32 +pkg syscall (openbsd-386), type Stat_t struct, Qspare [2]int64 +pkg syscall (openbsd-386), type Statfs_t struct, F_ctime uint32 +pkg syscall (openbsd-386), type Statfs_t struct, F_spare [3]uint32 +pkg syscall (openbsd-386), type Timespec struct, Sec int32 +pkg syscall (openbsd-386), type Timeval struct, Sec int32 +pkg syscall (openbsd-386-cgo), const BIOCGRTIMEOUT = 1074283118 +pkg syscall (openbsd-386-cgo), const BIOCSRTIMEOUT = 2148024941 +pkg syscall (openbsd-386-cgo), const RTF_FMASK = 63496 +pkg syscall (openbsd-386-cgo), const RTM_VERSION = 4 +pkg syscall (openbsd-386-cgo), const SIOCBRDGDADDR = 2150132039 +pkg syscall (openbsd-386-cgo), const SIOCBRDGGPARAM = 3224922456 +pkg syscall (openbsd-386-cgo), const SIOCBRDGSADDR = 3223873860 +pkg syscall (openbsd-386-cgo), const SYS_CLOCK_GETRES = 234 +pkg syscall (openbsd-386-cgo), const SYS_CLOCK_GETTIME = 232 +pkg syscall (openbsd-386-cgo), const SYS_CLOCK_SETTIME = 233 +pkg syscall (openbsd-386-cgo), const SYS_FHSTATFS = 309 +pkg syscall (openbsd-386-cgo), const SYS_FSTAT = 292 +pkg syscall (openbsd-386-cgo), const SYS_FSTATAT = 316 +pkg syscall (openbsd-386-cgo), const SYS_FSTATFS = 308 +pkg syscall (openbsd-386-cgo), const SYS_FUTIMENS = 327 +pkg syscall (openbsd-386-cgo), const SYS_FUTIMES = 206 +pkg syscall (openbsd-386-cgo), const SYS_GETDIRENTRIES = 312 +pkg syscall (openbsd-386-cgo), const SYS_GETDIRENTRIES ideal-int +pkg syscall (openbsd-386-cgo), const SYS_GETFSSTAT = 306 +pkg syscall (openbsd-386-cgo), const SYS_GETITIMER = 86 +pkg syscall (openbsd-386-cgo), const SYS_GETRUSAGE = 117 +pkg syscall (openbsd-386-cgo), const SYS_GETTIMEOFDAY = 116 +pkg syscall (openbsd-386-cgo), const SYS_KEVENT = 270 +pkg syscall (openbsd-386-cgo), const SYS_LSTAT = 293 +pkg syscall (openbsd-386-cgo), const SYS_NANOSLEEP = 240 +pkg syscall (openbsd-386-cgo), const SYS_SELECT = 93 +pkg syscall (openbsd-386-cgo), const SYS_SETITIMER = 83 +pkg syscall (openbsd-386-cgo), const SYS_SETTIMEOFDAY = 122 +pkg syscall (openbsd-386-cgo), const SYS_STAT = 291 +pkg syscall (openbsd-386-cgo), const SYS_STATFS = 307 +pkg syscall (openbsd-386-cgo), const SYS_UTIMENSAT = 326 +pkg syscall (openbsd-386-cgo), const SYS_UTIMES = 138 +pkg syscall (openbsd-386-cgo), const SYS_WAIT4 = 7 +pkg syscall (openbsd-386-cgo), const SYS___THRSLEEP = 300 +pkg syscall (openbsd-386-cgo), const SizeofIfData = 208 +pkg syscall (openbsd-386-cgo), const SizeofIfMsghdr = 232 +pkg syscall (openbsd-386-cgo), const SizeofRtMetrics = 48 +pkg syscall (openbsd-386-cgo), const SizeofRtMsghdr = 88 +pkg syscall (openbsd-386-cgo), const TIOCGTSTAMP = 1074295899 +pkg syscall (openbsd-386-cgo), type Dirent struct, Fileno uint32 +pkg syscall (openbsd-386-cgo), type FdSet struct, Bits [32]int32 +pkg syscall (openbsd-386-cgo), type Kevent_t struct, Data int32 +pkg syscall (openbsd-386-cgo), type Mclpool struct, Grown uint32 +pkg syscall (openbsd-386-cgo), type RtMetrics struct, Expire uint32 +pkg syscall (openbsd-386-cgo), type Stat_t struct, Ino uint32 +pkg syscall (openbsd-386-cgo), type Stat_t struct, Lspare0 int32 +pkg syscall (openbsd-386-cgo), type Stat_t struct, Lspare1 int32 +pkg syscall (openbsd-386-cgo), type Stat_t struct, Qspare [2]int64 +pkg syscall (openbsd-386-cgo), type Statfs_t struct, F_ctime uint32 +pkg syscall (openbsd-386-cgo), type Statfs_t struct, F_spare [3]uint32 +pkg syscall (openbsd-386-cgo), type Timespec struct, Sec int32 +pkg syscall (openbsd-386-cgo), type Timeval struct, Sec int32 +pkg syscall (openbsd-amd64), const CCR0_FLUSH = 16 +pkg syscall (openbsd-amd64), const CCR0_FLUSH ideal-int +pkg syscall (openbsd-amd64), const CPUID_CFLUSH = 524288 +pkg syscall (openbsd-amd64), const CPUID_CFLUSH ideal-int +pkg syscall (openbsd-amd64), const EFER_LMA = 1024 +pkg syscall (openbsd-amd64), const EFER_LMA ideal-int +pkg syscall (openbsd-amd64), const EFER_LME = 256 +pkg syscall (openbsd-amd64), const EFER_LME ideal-int +pkg syscall (openbsd-amd64), const EFER_NXE = 2048 +pkg syscall (openbsd-amd64), const EFER_NXE ideal-int +pkg syscall (openbsd-amd64), const EFER_SCE = 1 +pkg syscall (openbsd-amd64), const EFER_SCE ideal-int +pkg syscall (openbsd-amd64), const PMC5_PIPELINE_FLUSH = 21 +pkg syscall (openbsd-amd64), const PMC5_PIPELINE_FLUSH ideal-int +pkg syscall (openbsd-amd64), const RTF_FMASK = 63496 +pkg syscall (openbsd-amd64), const RTM_VERSION = 4 +pkg syscall (openbsd-amd64), const SIOCBRDGDADDR = 2150132039 +pkg syscall (openbsd-amd64), const SIOCBRDGSADDR = 3223873860 +pkg syscall (openbsd-amd64), const SYS_CLOCK_GETRES = 234 +pkg syscall (openbsd-amd64), const SYS_CLOCK_GETTIME = 232 +pkg syscall (openbsd-amd64), const SYS_CLOCK_SETTIME = 233 +pkg syscall (openbsd-amd64), const SYS_FHSTATFS = 309 +pkg syscall (openbsd-amd64), const SYS_FSTAT = 292 +pkg syscall (openbsd-amd64), const SYS_FSTATAT = 316 +pkg syscall (openbsd-amd64), const SYS_FSTATFS = 308 +pkg syscall (openbsd-amd64), const SYS_FUTIMENS = 327 +pkg syscall (openbsd-amd64), const SYS_FUTIMES = 206 +pkg syscall (openbsd-amd64), const SYS_GETDIRENTRIES = 312 +pkg syscall (openbsd-amd64), const SYS_GETDIRENTRIES ideal-int +pkg syscall (openbsd-amd64), const SYS_GETFSSTAT = 306 +pkg syscall (openbsd-amd64), const SYS_GETITIMER = 86 +pkg syscall (openbsd-amd64), const SYS_GETRUSAGE = 117 +pkg syscall (openbsd-amd64), const SYS_GETTIMEOFDAY = 116 +pkg syscall (openbsd-amd64), const SYS_KEVENT = 270 +pkg syscall (openbsd-amd64), const SYS_LSTAT = 293 +pkg syscall (openbsd-amd64), const SYS_NANOSLEEP = 240 +pkg syscall (openbsd-amd64), const SYS_SELECT = 93 +pkg syscall (openbsd-amd64), const SYS_SETITIMER = 83 +pkg syscall (openbsd-amd64), const SYS_SETTIMEOFDAY = 122 +pkg syscall (openbsd-amd64), const SYS_STAT = 291 +pkg syscall (openbsd-amd64), const SYS_STATFS = 307 +pkg syscall (openbsd-amd64), const SYS_UTIMENSAT = 326 +pkg syscall (openbsd-amd64), const SYS_UTIMES = 138 +pkg syscall (openbsd-amd64), const SYS_WAIT4 = 7 +pkg syscall (openbsd-amd64), const SYS___THRSLEEP = 300 +pkg syscall (openbsd-amd64), const SizeofRtMetrics = 48 +pkg syscall (openbsd-amd64), const SizeofRtMsghdr = 88 +pkg syscall (openbsd-amd64), type Dirent struct, Fileno uint32 +pkg syscall (openbsd-amd64), type FdSet struct, Bits [32]int32 +pkg syscall (openbsd-amd64), type Kevent_t struct, Data int32 +pkg syscall (openbsd-amd64), type Kevent_t struct, Ident uint32 +pkg syscall (openbsd-amd64), type Mclpool struct, Grown uint32 +pkg syscall (openbsd-amd64), type RtMetrics struct, Expire uint32 +pkg syscall (openbsd-amd64), type Stat_t struct, Ino uint32 +pkg syscall (openbsd-amd64), type Stat_t struct, Lspare0 int32 +pkg syscall (openbsd-amd64), type Stat_t struct, Lspare1 int32 +pkg syscall (openbsd-amd64), type Stat_t struct, Qspare [2]int64 +pkg syscall (openbsd-amd64), type Statfs_t struct, F_ctime uint32 +pkg syscall (openbsd-amd64), type Statfs_t struct, F_spare [3]uint32 +pkg syscall (openbsd-amd64), type Statfs_t struct, Pad_cgo_1 [4]uint8 +pkg syscall (openbsd-amd64), type Timespec struct, Pad_cgo_0 [4]uint8 +pkg syscall (openbsd-amd64), type Timespec struct, Sec int32 +pkg syscall (openbsd-amd64-cgo), const CCR0_FLUSH = 16 +pkg syscall (openbsd-amd64-cgo), const CCR0_FLUSH ideal-int +pkg syscall (openbsd-amd64-cgo), const CPUID_CFLUSH = 524288 +pkg syscall (openbsd-amd64-cgo), const CPUID_CFLUSH ideal-int +pkg syscall (openbsd-amd64-cgo), const EFER_LMA = 1024 +pkg syscall (openbsd-amd64-cgo), const EFER_LMA ideal-int +pkg syscall (openbsd-amd64-cgo), const EFER_LME = 256 +pkg syscall (openbsd-amd64-cgo), const EFER_LME ideal-int +pkg syscall (openbsd-amd64-cgo), const EFER_NXE = 2048 +pkg syscall (openbsd-amd64-cgo), const EFER_NXE ideal-int +pkg syscall (openbsd-amd64-cgo), const EFER_SCE = 1 +pkg syscall (openbsd-amd64-cgo), const EFER_SCE ideal-int +pkg syscall (openbsd-amd64-cgo), const PMC5_PIPELINE_FLUSH = 21 +pkg syscall (openbsd-amd64-cgo), const PMC5_PIPELINE_FLUSH ideal-int +pkg syscall (openbsd-amd64-cgo), const RTF_FMASK = 63496 +pkg syscall (openbsd-amd64-cgo), const RTM_VERSION = 4 +pkg syscall (openbsd-amd64-cgo), const SIOCBRDGDADDR = 2150132039 +pkg syscall (openbsd-amd64-cgo), const SIOCBRDGSADDR = 3223873860 +pkg syscall (openbsd-amd64-cgo), const SYS_CLOCK_GETRES = 234 +pkg syscall (openbsd-amd64-cgo), const SYS_CLOCK_GETTIME = 232 +pkg syscall (openbsd-amd64-cgo), const SYS_CLOCK_SETTIME = 233 +pkg syscall (openbsd-amd64-cgo), const SYS_FHSTATFS = 309 +pkg syscall (openbsd-amd64-cgo), const SYS_FSTAT = 292 +pkg syscall (openbsd-amd64-cgo), const SYS_FSTATAT = 316 +pkg syscall (openbsd-amd64-cgo), const SYS_FSTATFS = 308 +pkg syscall (openbsd-amd64-cgo), const SYS_FUTIMENS = 327 +pkg syscall (openbsd-amd64-cgo), const SYS_FUTIMES = 206 +pkg syscall (openbsd-amd64-cgo), const SYS_GETDIRENTRIES = 312 +pkg syscall (openbsd-amd64-cgo), const SYS_GETDIRENTRIES ideal-int +pkg syscall (openbsd-amd64-cgo), const SYS_GETFSSTAT = 306 +pkg syscall (openbsd-amd64-cgo), const SYS_GETITIMER = 86 +pkg syscall (openbsd-amd64-cgo), const SYS_GETRUSAGE = 117 +pkg syscall (openbsd-amd64-cgo), const SYS_GETTIMEOFDAY = 116 +pkg syscall (openbsd-amd64-cgo), const SYS_KEVENT = 270 +pkg syscall (openbsd-amd64-cgo), const SYS_LSTAT = 293 +pkg syscall (openbsd-amd64-cgo), const SYS_NANOSLEEP = 240 +pkg syscall (openbsd-amd64-cgo), const SYS_SELECT = 93 +pkg syscall (openbsd-amd64-cgo), const SYS_SETITIMER = 83 +pkg syscall (openbsd-amd64-cgo), const SYS_SETTIMEOFDAY = 122 +pkg syscall (openbsd-amd64-cgo), const SYS_STAT = 291 +pkg syscall (openbsd-amd64-cgo), const SYS_STATFS = 307 +pkg syscall (openbsd-amd64-cgo), const SYS_UTIMENSAT = 326 +pkg syscall (openbsd-amd64-cgo), const SYS_UTIMES = 138 +pkg syscall (openbsd-amd64-cgo), const SYS_WAIT4 = 7 +pkg syscall (openbsd-amd64-cgo), const SYS___THRSLEEP = 300 +pkg syscall (openbsd-amd64-cgo), const SizeofRtMetrics = 48 +pkg syscall (openbsd-amd64-cgo), const SizeofRtMsghdr = 88 +pkg syscall (openbsd-amd64-cgo), type Dirent struct, Fileno uint32 +pkg syscall (openbsd-amd64-cgo), type FdSet struct, Bits [32]int32 +pkg syscall (openbsd-amd64-cgo), type Kevent_t struct, Data int32 +pkg syscall (openbsd-amd64-cgo), type Kevent_t struct, Ident uint32 +pkg syscall (openbsd-amd64-cgo), type Mclpool struct, Grown uint32 +pkg syscall (openbsd-amd64-cgo), type RtMetrics struct, Expire uint32 +pkg syscall (openbsd-amd64-cgo), type Stat_t struct, Ino uint32 +pkg syscall (openbsd-amd64-cgo), type Stat_t struct, Lspare0 int32 +pkg syscall (openbsd-amd64-cgo), type Stat_t struct, Lspare1 int32 +pkg syscall (openbsd-amd64-cgo), type Stat_t struct, Qspare [2]int64 +pkg syscall (openbsd-amd64-cgo), type Statfs_t struct, F_ctime uint32 +pkg syscall (openbsd-amd64-cgo), type Statfs_t struct, F_spare [3]uint32 +pkg syscall (openbsd-amd64-cgo), type Statfs_t struct, Pad_cgo_1 [4]uint8 +pkg syscall (openbsd-amd64-cgo), type Timespec struct, Pad_cgo_0 [4]uint8 +pkg syscall (openbsd-amd64-cgo), type Timespec struct, Sec int32 +pkg unicode, const Version = "6.2.0" +pkg syscall (freebsd-386), const AF_MAX = 38 +pkg syscall (freebsd-386), const DLT_MATCHING_MAX = 242 +pkg syscall (freebsd-386), const ELAST = 94 +pkg syscall (freebsd-386), const O_CLOEXEC = 0 +pkg syscall (freebsd-386-cgo), const AF_MAX = 38 +pkg syscall (freebsd-386-cgo), const DLT_MATCHING_MAX = 242 +pkg syscall (freebsd-386-cgo), const ELAST = 94 +pkg syscall (freebsd-386-cgo), const O_CLOEXEC = 0 +pkg syscall (freebsd-amd64), const AF_MAX = 38 +pkg syscall (freebsd-amd64), const DLT_MATCHING_MAX = 242 +pkg syscall (freebsd-amd64), const ELAST = 94 +pkg syscall (freebsd-amd64), const O_CLOEXEC = 0 +pkg syscall (freebsd-amd64-cgo), const AF_MAX = 38 +pkg syscall (freebsd-amd64-cgo), const DLT_MATCHING_MAX = 242 +pkg syscall (freebsd-amd64-cgo), const ELAST = 94 +pkg syscall (freebsd-amd64-cgo), const O_CLOEXEC = 0 +pkg syscall (freebsd-arm), const AF_MAX = 38 +pkg syscall (freebsd-arm), const BIOCGRTIMEOUT = 1074545262 +pkg syscall (freebsd-arm), const BIOCSRTIMEOUT = 2148287085 +pkg syscall (freebsd-arm), const ELAST = 94 +pkg syscall (freebsd-arm), const O_CLOEXEC = 0 +pkg syscall (freebsd-arm), const SIOCAIFADDR = 2151967019 +pkg syscall (freebsd-arm), const SIOCGIFSTATUS = 3274991931 +pkg syscall (freebsd-arm), const SIOCSIFPHYADDR = 2151967046 +pkg syscall (freebsd-arm), const SYS_CAP_FCNTLS_GET = 537 +pkg syscall (freebsd-arm), const SYS_CAP_FCNTLS_GET ideal-int +pkg syscall (freebsd-arm), const SYS_CAP_FCNTLS_LIMIT = 536 +pkg syscall (freebsd-arm), const SYS_CAP_FCNTLS_LIMIT ideal-int +pkg syscall (freebsd-arm), const SYS_CAP_IOCTLS_GET = 535 +pkg syscall (freebsd-arm), const SYS_CAP_IOCTLS_GET ideal-int +pkg syscall (freebsd-arm), const SYS_CAP_IOCTLS_LIMIT = 534 +pkg syscall (freebsd-arm), const SYS_CAP_IOCTLS_LIMIT ideal-int +pkg syscall (freebsd-arm), const SYS_CAP_RIGHTS_GET = 515 +pkg syscall (freebsd-arm), const SYS_CAP_RIGHTS_GET ideal-int +pkg syscall (freebsd-arm), const SYS_CAP_RIGHTS_LIMIT = 533 +pkg syscall (freebsd-arm), const SYS_CAP_RIGHTS_LIMIT ideal-int +pkg syscall (freebsd-arm), const SizeofBpfHdr = 24 +pkg syscall (freebsd-arm), const SizeofIfData = 88 +pkg syscall (freebsd-arm), const SizeofIfMsghdr = 104 +pkg syscall (freebsd-arm), const SizeofSockaddrDatalink = 56 +pkg syscall (freebsd-arm), const SizeofSockaddrUnix = 108 +pkg syscall (freebsd-arm), const TIOCTIMESTAMP = 1074558041 +pkg syscall (freebsd-arm), type BpfHdr struct, Pad_cgo_0 [2]uint8 +pkg syscall (freebsd-arm), type RawSockaddrDatalink struct, Pad_cgo_0 [2]uint8 +pkg syscall (freebsd-arm), type RawSockaddrUnix struct, Pad_cgo_0 [2]uint8 +pkg syscall (freebsd-arm), type Stat_t struct, Pad_cgo_0 [4]uint8 +pkg syscall (freebsd-arm-cgo), const AF_MAX = 38 +pkg syscall (freebsd-arm-cgo), const BIOCGRTIMEOUT = 1074545262 +pkg syscall (freebsd-arm-cgo), const BIOCSRTIMEOUT = 2148287085 +pkg syscall (freebsd-arm-cgo), const ELAST = 94 +pkg syscall (freebsd-arm-cgo), const O_CLOEXEC = 0 +pkg syscall (freebsd-arm-cgo), const SIOCAIFADDR = 2151967019 +pkg syscall (freebsd-arm-cgo), const SIOCGIFSTATUS = 3274991931 +pkg syscall (freebsd-arm-cgo), const SIOCSIFPHYADDR = 2151967046 +pkg syscall (freebsd-arm-cgo), const SYS_CAP_FCNTLS_GET = 537 +pkg syscall (freebsd-arm-cgo), const SYS_CAP_FCNTLS_GET ideal-int +pkg syscall (freebsd-arm-cgo), const SYS_CAP_FCNTLS_LIMIT = 536 +pkg syscall (freebsd-arm-cgo), const SYS_CAP_FCNTLS_LIMIT ideal-int +pkg syscall (freebsd-arm-cgo), const SYS_CAP_IOCTLS_GET = 535 +pkg syscall (freebsd-arm-cgo), const SYS_CAP_IOCTLS_GET ideal-int +pkg syscall (freebsd-arm-cgo), const SYS_CAP_IOCTLS_LIMIT = 534 +pkg syscall (freebsd-arm-cgo), const SYS_CAP_IOCTLS_LIMIT ideal-int +pkg syscall (freebsd-arm-cgo), const SYS_CAP_RIGHTS_GET = 515 +pkg syscall (freebsd-arm-cgo), const SYS_CAP_RIGHTS_GET ideal-int +pkg syscall (freebsd-arm-cgo), const SYS_CAP_RIGHTS_LIMIT = 533 +pkg syscall (freebsd-arm-cgo), const SYS_CAP_RIGHTS_LIMIT ideal-int +pkg syscall (freebsd-arm-cgo), const SizeofBpfHdr = 24 +pkg syscall (freebsd-arm-cgo), const SizeofIfData = 88 +pkg syscall (freebsd-arm-cgo), const SizeofIfMsghdr = 104 +pkg syscall (freebsd-arm-cgo), const SizeofSockaddrDatalink = 56 +pkg syscall (freebsd-arm-cgo), const SizeofSockaddrUnix = 108 +pkg syscall (freebsd-arm-cgo), const TIOCTIMESTAMP = 1074558041 +pkg syscall (freebsd-arm-cgo), type BpfHdr struct, Pad_cgo_0 [2]uint8 +pkg syscall (freebsd-arm-cgo), type RawSockaddrDatalink struct, Pad_cgo_0 [2]uint8 +pkg syscall (freebsd-arm-cgo), type RawSockaddrUnix struct, Pad_cgo_0 [2]uint8 +pkg syscall (freebsd-arm-cgo), type Stat_t struct, Pad_cgo_0 [4]uint8 +pkg syscall (netbsd-arm), const SizeofIfData = 132 +pkg syscall (netbsd-arm), type IfMsghdr struct, Pad_cgo_1 [4]uint8 +pkg syscall (netbsd-arm-cgo), const SizeofIfData = 132 +pkg syscall (netbsd-arm-cgo), type IfMsghdr struct, Pad_cgo_1 [4]uint8 diff --git a/api/go1.3.txt b/api/go1.3.txt new file mode 100644 index 000000000..0474277c4 --- /dev/null +++ b/api/go1.3.txt @@ -0,0 +1,2053 @@ +pkg archive/tar, const TypeGNUSparse = 83 +pkg archive/tar, const TypeGNUSparse ideal-char +pkg archive/tar, type Header struct, Xattrs map[string]string +pkg compress/gzip, method (*Reader) Reset(io.Reader) error +pkg crypto/tls, const CurveP256 = 23 +pkg crypto/tls, const CurveP256 CurveID +pkg crypto/tls, const CurveP384 = 24 +pkg crypto/tls, const CurveP384 CurveID +pkg crypto/tls, const CurveP521 = 25 +pkg crypto/tls, const CurveP521 CurveID +pkg crypto/tls, func DialWithDialer(*net.Dialer, string, string, *Config) (*Conn, error) +pkg crypto/tls, func NewLRUClientSessionCache(int) ClientSessionCache +pkg crypto/tls, type ClientSessionCache interface { Get, Put } +pkg crypto/tls, type ClientSessionCache interface, Get(string) (*ClientSessionState, bool) +pkg crypto/tls, type ClientSessionCache interface, Put(string, *ClientSessionState) +pkg crypto/tls, type ClientSessionState struct +pkg crypto/tls, type Config struct, ClientSessionCache ClientSessionCache +pkg crypto/tls, type Config struct, CurvePreferences []CurveID +pkg crypto/tls, type ConnectionState struct, Version uint16 +pkg crypto/tls, type CurveID uint16 +pkg crypto/x509, func CreateCertificateRequest(io.Reader, *CertificateRequest, interface{}) ([]uint8, error) +pkg crypto/x509, func ParseCertificateRequest([]uint8) (*CertificateRequest, error) +pkg crypto/x509, type CertificateRequest struct +pkg crypto/x509, type CertificateRequest struct, Attributes []pkix.AttributeTypeAndValueSET +pkg crypto/x509, type CertificateRequest struct, DNSNames []string +pkg crypto/x509, type CertificateRequest struct, EmailAddresses []string +pkg crypto/x509, type CertificateRequest struct, Extensions []pkix.Extension +pkg crypto/x509, type CertificateRequest struct, ExtraExtensions []pkix.Extension +pkg crypto/x509, type CertificateRequest struct, IPAddresses []net.IP +pkg crypto/x509, type CertificateRequest struct, PublicKey interface{} +pkg crypto/x509, type CertificateRequest struct, PublicKeyAlgorithm PublicKeyAlgorithm +pkg crypto/x509, type CertificateRequest struct, Raw []uint8 +pkg crypto/x509, type CertificateRequest struct, RawSubject []uint8 +pkg crypto/x509, type CertificateRequest struct, RawSubjectPublicKeyInfo []uint8 +pkg crypto/x509, type CertificateRequest struct, RawTBSCertificateRequest []uint8 +pkg crypto/x509, type CertificateRequest struct, Signature []uint8 +pkg crypto/x509, type CertificateRequest struct, SignatureAlgorithm SignatureAlgorithm +pkg crypto/x509, type CertificateRequest struct, Subject pkix.Name +pkg crypto/x509, type CertificateRequest struct, Version int +pkg crypto/x509/pkix, type AttributeTypeAndValueSET struct +pkg crypto/x509/pkix, type AttributeTypeAndValueSET struct, Type asn1.ObjectIdentifier +pkg crypto/x509/pkix, type AttributeTypeAndValueSET struct, Value [][]AttributeTypeAndValue +pkg debug/dwarf, const TagCondition = 63 +pkg debug/dwarf, const TagCondition Tag +pkg debug/dwarf, const TagRvalueReferenceType = 66 +pkg debug/dwarf, const TagRvalueReferenceType Tag +pkg debug/dwarf, const TagSharedType = 64 +pkg debug/dwarf, const TagSharedType Tag +pkg debug/dwarf, const TagTemplateAlias = 67 +pkg debug/dwarf, const TagTemplateAlias Tag +pkg debug/dwarf, const TagTypeUnit = 65 +pkg debug/dwarf, const TagTypeUnit Tag +pkg debug/dwarf, method (*Data) AddTypes(string, []uint8) error +pkg debug/macho, const CpuArm = 12 +pkg debug/macho, const CpuArm Cpu +pkg debug/macho, const CpuPpc = 18 +pkg debug/macho, const CpuPpc Cpu +pkg debug/macho, const CpuPpc64 = 16777234 +pkg debug/macho, const CpuPpc64 Cpu +pkg debug/macho, const MagicFat = 3405691582 +pkg debug/macho, const MagicFat uint32 +pkg debug/macho, const TypeBundle = 8 +pkg debug/macho, const TypeBundle Type +pkg debug/macho, const TypeDylib = 6 +pkg debug/macho, const TypeDylib Type +pkg debug/macho, func NewFatFile(io.ReaderAt) (*FatFile, error) +pkg debug/macho, func OpenFat(string) (*FatFile, error) +pkg debug/macho, method (*FatFile) Close() error +pkg debug/macho, method (FatArch) Close() error +pkg debug/macho, method (FatArch) DWARF() (*dwarf.Data, error) +pkg debug/macho, method (FatArch) ImportedLibraries() ([]string, error) +pkg debug/macho, method (FatArch) ImportedSymbols() ([]string, error) +pkg debug/macho, method (FatArch) Section(string) *Section +pkg debug/macho, method (FatArch) Segment(string) *Segment +pkg debug/macho, type FatArch struct +pkg debug/macho, type FatArch struct, embedded *File +pkg debug/macho, type FatArch struct, embedded FatArchHeader +pkg debug/macho, type FatArchHeader struct +pkg debug/macho, type FatArchHeader struct, Align uint32 +pkg debug/macho, type FatArchHeader struct, Cpu Cpu +pkg debug/macho, type FatArchHeader struct, Offset uint32 +pkg debug/macho, type FatArchHeader struct, Size uint32 +pkg debug/macho, type FatArchHeader struct, SubCpu uint32 +pkg debug/macho, type FatFile struct +pkg debug/macho, type FatFile struct, Arches []FatArch +pkg debug/macho, type FatFile struct, Magic uint32 +pkg debug/macho, var ErrNotFat *FormatError +pkg debug/pe, type DataDirectory struct +pkg debug/pe, type DataDirectory struct, Size uint32 +pkg debug/pe, type DataDirectory struct, VirtualAddress uint32 +pkg debug/pe, type File struct, OptionalHeader interface{} +pkg debug/pe, type OptionalHeader32 struct +pkg debug/pe, type OptionalHeader32 struct, AddressOfEntryPoint uint32 +pkg debug/pe, type OptionalHeader32 struct, BaseOfCode uint32 +pkg debug/pe, type OptionalHeader32 struct, BaseOfData uint32 +pkg debug/pe, type OptionalHeader32 struct, CheckSum uint32 +pkg debug/pe, type OptionalHeader32 struct, DataDirectory [16]DataDirectory +pkg debug/pe, type OptionalHeader32 struct, DllCharacteristics uint16 +pkg debug/pe, type OptionalHeader32 struct, FileAlignment uint32 +pkg debug/pe, type OptionalHeader32 struct, ImageBase uint32 +pkg debug/pe, type OptionalHeader32 struct, LoaderFlags uint32 +pkg debug/pe, type OptionalHeader32 struct, Magic uint16 +pkg debug/pe, type OptionalHeader32 struct, MajorImageVersion uint16 +pkg debug/pe, type OptionalHeader32 struct, MajorLinkerVersion uint8 +pkg debug/pe, type OptionalHeader32 struct, MajorOperatingSystemVersion uint16 +pkg debug/pe, type OptionalHeader32 struct, MajorSubsystemVersion uint16 +pkg debug/pe, type OptionalHeader32 struct, MinorImageVersion uint16 +pkg debug/pe, type OptionalHeader32 struct, MinorLinkerVersion uint8 +pkg debug/pe, type OptionalHeader32 struct, MinorOperatingSystemVersion uint16 +pkg debug/pe, type OptionalHeader32 struct, MinorSubsystemVersion uint16 +pkg debug/pe, type OptionalHeader32 struct, NumberOfRvaAndSizes uint32 +pkg debug/pe, type OptionalHeader32 struct, SectionAlignment uint32 +pkg debug/pe, type OptionalHeader32 struct, SizeOfCode uint32 +pkg debug/pe, type OptionalHeader32 struct, SizeOfHeaders uint32 +pkg debug/pe, type OptionalHeader32 struct, SizeOfHeapCommit uint32 +pkg debug/pe, type OptionalHeader32 struct, SizeOfHeapReserve uint32 +pkg debug/pe, type OptionalHeader32 struct, SizeOfImage uint32 +pkg debug/pe, type OptionalHeader32 struct, SizeOfInitializedData uint32 +pkg debug/pe, type OptionalHeader32 struct, SizeOfStackCommit uint32 +pkg debug/pe, type OptionalHeader32 struct, SizeOfStackReserve uint32 +pkg debug/pe, type OptionalHeader32 struct, SizeOfUninitializedData uint32 +pkg debug/pe, type OptionalHeader32 struct, Subsystem uint16 +pkg debug/pe, type OptionalHeader32 struct, Win32VersionValue uint32 +pkg debug/pe, type OptionalHeader64 struct +pkg debug/pe, type OptionalHeader64 struct, AddressOfEntryPoint uint32 +pkg debug/pe, type OptionalHeader64 struct, BaseOfCode uint32 +pkg debug/pe, type OptionalHeader64 struct, CheckSum uint32 +pkg debug/pe, type OptionalHeader64 struct, DataDirectory [16]DataDirectory +pkg debug/pe, type OptionalHeader64 struct, DllCharacteristics uint16 +pkg debug/pe, type OptionalHeader64 struct, FileAlignment uint32 +pkg debug/pe, type OptionalHeader64 struct, ImageBase uint64 +pkg debug/pe, type OptionalHeader64 struct, LoaderFlags uint32 +pkg debug/pe, type OptionalHeader64 struct, Magic uint16 +pkg debug/pe, type OptionalHeader64 struct, MajorImageVersion uint16 +pkg debug/pe, type OptionalHeader64 struct, MajorLinkerVersion uint8 +pkg debug/pe, type OptionalHeader64 struct, MajorOperatingSystemVersion uint16 +pkg debug/pe, type OptionalHeader64 struct, MajorSubsystemVersion uint16 +pkg debug/pe, type OptionalHeader64 struct, MinorImageVersion uint16 +pkg debug/pe, type OptionalHeader64 struct, MinorLinkerVersion uint8 +pkg debug/pe, type OptionalHeader64 struct, MinorOperatingSystemVersion uint16 +pkg debug/pe, type OptionalHeader64 struct, MinorSubsystemVersion uint16 +pkg debug/pe, type OptionalHeader64 struct, NumberOfRvaAndSizes uint32 +pkg debug/pe, type OptionalHeader64 struct, SectionAlignment uint32 +pkg debug/pe, type OptionalHeader64 struct, SizeOfCode uint32 +pkg debug/pe, type OptionalHeader64 struct, SizeOfHeaders uint32 +pkg debug/pe, type OptionalHeader64 struct, SizeOfHeapCommit uint64 +pkg debug/pe, type OptionalHeader64 struct, SizeOfHeapReserve uint64 +pkg debug/pe, type OptionalHeader64 struct, SizeOfImage uint32 +pkg debug/pe, type OptionalHeader64 struct, SizeOfInitializedData uint32 +pkg debug/pe, type OptionalHeader64 struct, SizeOfStackCommit uint64 +pkg debug/pe, type OptionalHeader64 struct, SizeOfStackReserve uint64 +pkg debug/pe, type OptionalHeader64 struct, SizeOfUninitializedData uint32 +pkg debug/pe, type OptionalHeader64 struct, Subsystem uint16 +pkg debug/pe, type OptionalHeader64 struct, Win32VersionValue uint32 +pkg debug/plan9obj, const Magic386 = 491 +pkg debug/plan9obj, const Magic386 ideal-int +pkg debug/plan9obj, const Magic64 = 32768 +pkg debug/plan9obj, const Magic64 ideal-int +pkg debug/plan9obj, const MagicAMD64 = 35479 +pkg debug/plan9obj, const MagicAMD64 ideal-int +pkg debug/plan9obj, const MagicARM = 1607 +pkg debug/plan9obj, const MagicARM ideal-int +pkg debug/plan9obj, func NewFile(io.ReaderAt) (*File, error) +pkg debug/plan9obj, func Open(string) (*File, error) +pkg debug/plan9obj, method (*File) Close() error +pkg debug/plan9obj, method (*File) Section(string) *Section +pkg debug/plan9obj, method (*File) Symbols() ([]Sym, error) +pkg debug/plan9obj, method (*Section) Data() ([]uint8, error) +pkg debug/plan9obj, method (*Section) Open() io.ReadSeeker +pkg debug/plan9obj, method (Section) ReadAt([]uint8, int64) (int, error) +pkg debug/plan9obj, type File struct +pkg debug/plan9obj, type File struct, Sections []*Section +pkg debug/plan9obj, type File struct, embedded FileHeader +pkg debug/plan9obj, type FileHeader struct +pkg debug/plan9obj, type FileHeader struct, Bss uint32 +pkg debug/plan9obj, type FileHeader struct, Entry uint64 +pkg debug/plan9obj, type FileHeader struct, Magic uint32 +pkg debug/plan9obj, type FileHeader struct, PtrSize int +pkg debug/plan9obj, type Section struct +pkg debug/plan9obj, type Section struct, embedded SectionHeader +pkg debug/plan9obj, type Section struct, embedded io.ReaderAt +pkg debug/plan9obj, type SectionHeader struct +pkg debug/plan9obj, type SectionHeader struct, Name string +pkg debug/plan9obj, type SectionHeader struct, Offset uint32 +pkg debug/plan9obj, type SectionHeader struct, Size uint32 +pkg debug/plan9obj, type Sym struct +pkg debug/plan9obj, type Sym struct, Name string +pkg debug/plan9obj, type Sym struct, Type int32 +pkg debug/plan9obj, type Sym struct, Value uint64 +pkg encoding/asn1, method (ObjectIdentifier) String() string +pkg go/build, type Package struct, MFiles []string +pkg math/big, method (*Int) MarshalText() ([]uint8, error) +pkg math/big, method (*Int) UnmarshalText([]uint8) error +pkg math/big, method (*Rat) MarshalText() ([]uint8, error) +pkg math/big, method (*Rat) UnmarshalText([]uint8) error +pkg net, type Dialer struct, KeepAlive time.Duration +pkg net/http, const StateActive = 1 +pkg net/http, const StateActive ConnState +pkg net/http, const StateClosed = 4 +pkg net/http, const StateClosed ConnState +pkg net/http, const StateHijacked = 3 +pkg net/http, const StateHijacked ConnState +pkg net/http, const StateIdle = 2 +pkg net/http, const StateIdle ConnState +pkg net/http, const StateNew = 0 +pkg net/http, const StateNew ConnState +pkg net/http, method (*Server) SetKeepAlivesEnabled(bool) +pkg net/http, method (ConnState) String() string +pkg net/http, type Client struct, Timeout time.Duration +pkg net/http, type ConnState int +pkg net/http, type Response struct, TLS *tls.ConnectionState +pkg net/http, type Server struct, ConnState func(net.Conn, ConnState) +pkg net/http, type Server struct, ErrorLog *log.Logger +pkg net/http, type Transport struct, TLSHandshakeTimeout time.Duration +pkg regexp/syntax, method (*Inst) MatchRunePos(int32) int +pkg regexp/syntax, method (InstOp) String() string +pkg runtime/debug, func SetPanicOnFault(bool) bool +pkg runtime/debug, func WriteHeapDump(uintptr) +pkg sync, method (*Pool) Get() interface{} +pkg sync, method (*Pool) Put(interface{}) +pkg sync, type Pool struct +pkg sync, type Pool struct, New func() interface{} +pkg syscall (darwin-386), func FcntlFlock(uintptr, int, *Flock_t) error +pkg syscall (darwin-386), func Mlock([]uint8) error +pkg syscall (darwin-386), func Mlockall(int) error +pkg syscall (darwin-386), func Mprotect([]uint8, int) error +pkg syscall (darwin-386), func Munlock([]uint8) error +pkg syscall (darwin-386), func Munlockall() error +pkg syscall (darwin-386), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error) +pkg syscall (darwin-386-cgo), func FcntlFlock(uintptr, int, *Flock_t) error +pkg syscall (darwin-386-cgo), func Mlock([]uint8) error +pkg syscall (darwin-386-cgo), func Mlockall(int) error +pkg syscall (darwin-386-cgo), func Mprotect([]uint8, int) error +pkg syscall (darwin-386-cgo), func Munlock([]uint8) error +pkg syscall (darwin-386-cgo), func Munlockall() error +pkg syscall (darwin-386-cgo), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error) +pkg syscall (darwin-amd64), func FcntlFlock(uintptr, int, *Flock_t) error +pkg syscall (darwin-amd64), func Mlock([]uint8) error +pkg syscall (darwin-amd64), func Mlockall(int) error +pkg syscall (darwin-amd64), func Mprotect([]uint8, int) error +pkg syscall (darwin-amd64), func Munlock([]uint8) error +pkg syscall (darwin-amd64), func Munlockall() error +pkg syscall (darwin-amd64), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error) +pkg syscall (darwin-amd64-cgo), func FcntlFlock(uintptr, int, *Flock_t) error +pkg syscall (darwin-amd64-cgo), func Mlock([]uint8) error +pkg syscall (darwin-amd64-cgo), func Mlockall(int) error +pkg syscall (darwin-amd64-cgo), func Mprotect([]uint8, int) error +pkg syscall (darwin-amd64-cgo), func Munlock([]uint8) error +pkg syscall (darwin-amd64-cgo), func Munlockall() error +pkg syscall (darwin-amd64-cgo), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error) +pkg syscall (freebsd-386), const AF_INET6_SDP = 42 +pkg syscall (freebsd-386), const AF_INET6_SDP ideal-int +pkg syscall (freebsd-386), const AF_INET_SDP = 40 +pkg syscall (freebsd-386), const AF_INET_SDP ideal-int +pkg syscall (freebsd-386), const AF_MAX = 42 +pkg syscall (freebsd-386), const DLT_MATCHING_MAX = 246 +pkg syscall (freebsd-386), const DLT_MPEG_2_TS = 243 +pkg syscall (freebsd-386), const DLT_MPEG_2_TS ideal-int +pkg syscall (freebsd-386), const DLT_NFC_LLCP = 245 +pkg syscall (freebsd-386), const DLT_NFC_LLCP ideal-int +pkg syscall (freebsd-386), const DLT_NG40 = 244 +pkg syscall (freebsd-386), const DLT_NG40 ideal-int +pkg syscall (freebsd-386), const ELAST = 96 +pkg syscall (freebsd-386), const ENOTRECOVERABLE = 95 +pkg syscall (freebsd-386), const ENOTRECOVERABLE Errno +pkg syscall (freebsd-386), const EOWNERDEAD = 96 +pkg syscall (freebsd-386), const EOWNERDEAD Errno +pkg syscall (freebsd-386), const EV_DROP = 4096 +pkg syscall (freebsd-386), const EV_DROP ideal-int +pkg syscall (freebsd-386), const IPPROTO_MPLS = 137 +pkg syscall (freebsd-386), const IPPROTO_MPLS ideal-int +pkg syscall (freebsd-386), const MAP_ALIGNED_SUPER = 16777216 +pkg syscall (freebsd-386), const MAP_ALIGNED_SUPER ideal-int +pkg syscall (freebsd-386), const MAP_ALIGNMENT_MASK = -16777216 +pkg syscall (freebsd-386), const MAP_ALIGNMENT_MASK ideal-int +pkg syscall (freebsd-386), const MAP_ALIGNMENT_SHIFT = 24 +pkg syscall (freebsd-386), const MAP_ALIGNMENT_SHIFT ideal-int +pkg syscall (freebsd-386), const MSG_CMSG_CLOEXEC = 262144 +pkg syscall (freebsd-386), const MSG_CMSG_CLOEXEC ideal-int +pkg syscall (freebsd-386), const NAME_MAX = 255 +pkg syscall (freebsd-386), const NAME_MAX ideal-int +pkg syscall (freebsd-386), const O_CLOEXEC = 1048576 +pkg syscall (freebsd-386), const RTF_GWFLAG_COMPAT = 2147483648 +pkg syscall (freebsd-386), const RTF_GWFLAG_COMPAT ideal-int +pkg syscall (freebsd-386), const RT_NORTREF = 2 +pkg syscall (freebsd-386), const RT_NORTREF ideal-int +pkg syscall (freebsd-386), const SIGLIBRT = 33 +pkg syscall (freebsd-386), const SIGLIBRT Signal +pkg syscall (freebsd-386), const SOCK_CLOEXEC = 268435456 +pkg syscall (freebsd-386), const SOCK_CLOEXEC ideal-int +pkg syscall (freebsd-386), const SOCK_NONBLOCK = 536870912 +pkg syscall (freebsd-386), const SOCK_NONBLOCK ideal-int +pkg syscall (freebsd-386), const SO_VENDOR = 2147483648 +pkg syscall (freebsd-386), const SO_VENDOR ideal-int +pkg syscall (freebsd-386), const SYS_ACCEPT4 = 541 +pkg syscall (freebsd-386), const SYS_ACCEPT4 ideal-int +pkg syscall (freebsd-386), const SYS_BINDAT = 538 +pkg syscall (freebsd-386), const SYS_BINDAT ideal-int +pkg syscall (freebsd-386), const SYS_CHFLAGSAT = 540 +pkg syscall (freebsd-386), const SYS_CHFLAGSAT ideal-int +pkg syscall (freebsd-386), const SYS_CONNECTAT = 539 +pkg syscall (freebsd-386), const SYS_CONNECTAT ideal-int +pkg syscall (freebsd-386), const SYS_PIPE2 = 542 +pkg syscall (freebsd-386), const SYS_PIPE2 ideal-int +pkg syscall (freebsd-386), const SYS_PROCCTL = 544 +pkg syscall (freebsd-386), const SYS_PROCCTL ideal-int +pkg syscall (freebsd-386), const TCP_VENDOR = 2147483648 +pkg syscall (freebsd-386), const TCP_VENDOR ideal-int +pkg syscall (freebsd-386), const WEXITED = 16 +pkg syscall (freebsd-386), const WEXITED ideal-int +pkg syscall (freebsd-386), const WTRAPPED = 32 +pkg syscall (freebsd-386), const WTRAPPED ideal-int +pkg syscall (freebsd-386), func Accept4(int, int) (int, Sockaddr, error) +pkg syscall (freebsd-386), func FcntlFlock(uintptr, int, *Flock_t) error +pkg syscall (freebsd-386), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error) +pkg syscall (freebsd-386), type Termios struct +pkg syscall (freebsd-386), type Termios struct, Cc [20]uint8 +pkg syscall (freebsd-386), type Termios struct, Cflag uint32 +pkg syscall (freebsd-386), type Termios struct, Iflag uint32 +pkg syscall (freebsd-386), type Termios struct, Ispeed uint32 +pkg syscall (freebsd-386), type Termios struct, Lflag uint32 +pkg syscall (freebsd-386), type Termios struct, Oflag uint32 +pkg syscall (freebsd-386), type Termios struct, Ospeed uint32 +pkg syscall (freebsd-386-cgo), const AF_INET6_SDP = 42 +pkg syscall (freebsd-386-cgo), const AF_INET6_SDP ideal-int +pkg syscall (freebsd-386-cgo), const AF_INET_SDP = 40 +pkg syscall (freebsd-386-cgo), const AF_INET_SDP ideal-int +pkg syscall (freebsd-386-cgo), const AF_MAX = 42 +pkg syscall (freebsd-386-cgo), const DLT_MATCHING_MAX = 246 +pkg syscall (freebsd-386-cgo), const DLT_MPEG_2_TS = 243 +pkg syscall (freebsd-386-cgo), const DLT_MPEG_2_TS ideal-int +pkg syscall (freebsd-386-cgo), const DLT_NFC_LLCP = 245 +pkg syscall (freebsd-386-cgo), const DLT_NFC_LLCP ideal-int +pkg syscall (freebsd-386-cgo), const DLT_NG40 = 244 +pkg syscall (freebsd-386-cgo), const DLT_NG40 ideal-int +pkg syscall (freebsd-386-cgo), const ELAST = 96 +pkg syscall (freebsd-386-cgo), const ENOTRECOVERABLE = 95 +pkg syscall (freebsd-386-cgo), const ENOTRECOVERABLE Errno +pkg syscall (freebsd-386-cgo), const EOWNERDEAD = 96 +pkg syscall (freebsd-386-cgo), const EOWNERDEAD Errno +pkg syscall (freebsd-386-cgo), const EV_DROP = 4096 +pkg syscall (freebsd-386-cgo), const EV_DROP ideal-int +pkg syscall (freebsd-386-cgo), const IPPROTO_MPLS = 137 +pkg syscall (freebsd-386-cgo), const IPPROTO_MPLS ideal-int +pkg syscall (freebsd-386-cgo), const MAP_ALIGNED_SUPER = 16777216 +pkg syscall (freebsd-386-cgo), const MAP_ALIGNED_SUPER ideal-int +pkg syscall (freebsd-386-cgo), const MAP_ALIGNMENT_MASK = -16777216 +pkg syscall (freebsd-386-cgo), const MAP_ALIGNMENT_MASK ideal-int +pkg syscall (freebsd-386-cgo), const MAP_ALIGNMENT_SHIFT = 24 +pkg syscall (freebsd-386-cgo), const MAP_ALIGNMENT_SHIFT ideal-int +pkg syscall (freebsd-386-cgo), const MSG_CMSG_CLOEXEC = 262144 +pkg syscall (freebsd-386-cgo), const MSG_CMSG_CLOEXEC ideal-int +pkg syscall (freebsd-386-cgo), const NAME_MAX = 255 +pkg syscall (freebsd-386-cgo), const NAME_MAX ideal-int +pkg syscall (freebsd-386-cgo), const O_CLOEXEC = 1048576 +pkg syscall (freebsd-386-cgo), const RTF_GWFLAG_COMPAT = 2147483648 +pkg syscall (freebsd-386-cgo), const RTF_GWFLAG_COMPAT ideal-int +pkg syscall (freebsd-386-cgo), const RT_NORTREF = 2 +pkg syscall (freebsd-386-cgo), const RT_NORTREF ideal-int +pkg syscall (freebsd-386-cgo), const SIGLIBRT = 33 +pkg syscall (freebsd-386-cgo), const SIGLIBRT Signal +pkg syscall (freebsd-386-cgo), const SOCK_CLOEXEC = 268435456 +pkg syscall (freebsd-386-cgo), const SOCK_CLOEXEC ideal-int +pkg syscall (freebsd-386-cgo), const SOCK_NONBLOCK = 536870912 +pkg syscall (freebsd-386-cgo), const SOCK_NONBLOCK ideal-int +pkg syscall (freebsd-386-cgo), const SO_VENDOR = 2147483648 +pkg syscall (freebsd-386-cgo), const SO_VENDOR ideal-int +pkg syscall (freebsd-386-cgo), const SYS_ACCEPT4 = 541 +pkg syscall (freebsd-386-cgo), const SYS_ACCEPT4 ideal-int +pkg syscall (freebsd-386-cgo), const SYS_BINDAT = 538 +pkg syscall (freebsd-386-cgo), const SYS_BINDAT ideal-int +pkg syscall (freebsd-386-cgo), const SYS_CHFLAGSAT = 540 +pkg syscall (freebsd-386-cgo), const SYS_CHFLAGSAT ideal-int +pkg syscall (freebsd-386-cgo), const SYS_CONNECTAT = 539 +pkg syscall (freebsd-386-cgo), const SYS_CONNECTAT ideal-int +pkg syscall (freebsd-386-cgo), const SYS_PIPE2 = 542 +pkg syscall (freebsd-386-cgo), const SYS_PIPE2 ideal-int +pkg syscall (freebsd-386-cgo), const SYS_PROCCTL = 544 +pkg syscall (freebsd-386-cgo), const SYS_PROCCTL ideal-int +pkg syscall (freebsd-386-cgo), const TCP_VENDOR = 2147483648 +pkg syscall (freebsd-386-cgo), const TCP_VENDOR ideal-int +pkg syscall (freebsd-386-cgo), const WEXITED = 16 +pkg syscall (freebsd-386-cgo), const WEXITED ideal-int +pkg syscall (freebsd-386-cgo), const WTRAPPED = 32 +pkg syscall (freebsd-386-cgo), const WTRAPPED ideal-int +pkg syscall (freebsd-386-cgo), func Accept4(int, int) (int, Sockaddr, error) +pkg syscall (freebsd-386-cgo), func FcntlFlock(uintptr, int, *Flock_t) error +pkg syscall (freebsd-386-cgo), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error) +pkg syscall (freebsd-386-cgo), type Termios struct +pkg syscall (freebsd-386-cgo), type Termios struct, Cc [20]uint8 +pkg syscall (freebsd-386-cgo), type Termios struct, Cflag uint32 +pkg syscall (freebsd-386-cgo), type Termios struct, Iflag uint32 +pkg syscall (freebsd-386-cgo), type Termios struct, Ispeed uint32 +pkg syscall (freebsd-386-cgo), type Termios struct, Lflag uint32 +pkg syscall (freebsd-386-cgo), type Termios struct, Oflag uint32 +pkg syscall (freebsd-386-cgo), type Termios struct, Ospeed uint32 +pkg syscall (freebsd-amd64), const AF_INET6_SDP = 42 +pkg syscall (freebsd-amd64), const AF_INET6_SDP ideal-int +pkg syscall (freebsd-amd64), const AF_INET_SDP = 40 +pkg syscall (freebsd-amd64), const AF_INET_SDP ideal-int +pkg syscall (freebsd-amd64), const AF_MAX = 42 +pkg syscall (freebsd-amd64), const DLT_MATCHING_MAX = 246 +pkg syscall (freebsd-amd64), const DLT_MPEG_2_TS = 243 +pkg syscall (freebsd-amd64), const DLT_MPEG_2_TS ideal-int +pkg syscall (freebsd-amd64), const DLT_NFC_LLCP = 245 +pkg syscall (freebsd-amd64), const DLT_NFC_LLCP ideal-int +pkg syscall (freebsd-amd64), const DLT_NG40 = 244 +pkg syscall (freebsd-amd64), const DLT_NG40 ideal-int +pkg syscall (freebsd-amd64), const ELAST = 96 +pkg syscall (freebsd-amd64), const ENOTRECOVERABLE = 95 +pkg syscall (freebsd-amd64), const ENOTRECOVERABLE Errno +pkg syscall (freebsd-amd64), const EOWNERDEAD = 96 +pkg syscall (freebsd-amd64), const EOWNERDEAD Errno +pkg syscall (freebsd-amd64), const EV_DROP = 4096 +pkg syscall (freebsd-amd64), const EV_DROP ideal-int +pkg syscall (freebsd-amd64), const IPPROTO_MPLS = 137 +pkg syscall (freebsd-amd64), const IPPROTO_MPLS ideal-int +pkg syscall (freebsd-amd64), const MAP_32BIT = 524288 +pkg syscall (freebsd-amd64), const MAP_32BIT ideal-int +pkg syscall (freebsd-amd64), const MAP_ALIGNED_SUPER = 16777216 +pkg syscall (freebsd-amd64), const MAP_ALIGNED_SUPER ideal-int +pkg syscall (freebsd-amd64), const MAP_ALIGNMENT_MASK = -16777216 +pkg syscall (freebsd-amd64), const MAP_ALIGNMENT_MASK ideal-int +pkg syscall (freebsd-amd64), const MAP_ALIGNMENT_SHIFT = 24 +pkg syscall (freebsd-amd64), const MAP_ALIGNMENT_SHIFT ideal-int +pkg syscall (freebsd-amd64), const MSG_CMSG_CLOEXEC = 262144 +pkg syscall (freebsd-amd64), const MSG_CMSG_CLOEXEC ideal-int +pkg syscall (freebsd-amd64), const NAME_MAX = 255 +pkg syscall (freebsd-amd64), const NAME_MAX ideal-int +pkg syscall (freebsd-amd64), const O_CLOEXEC = 1048576 +pkg syscall (freebsd-amd64), const RTF_GWFLAG_COMPAT = 2147483648 +pkg syscall (freebsd-amd64), const RTF_GWFLAG_COMPAT ideal-int +pkg syscall (freebsd-amd64), const RT_NORTREF = 2 +pkg syscall (freebsd-amd64), const RT_NORTREF ideal-int +pkg syscall (freebsd-amd64), const SIGLIBRT = 33 +pkg syscall (freebsd-amd64), const SIGLIBRT Signal +pkg syscall (freebsd-amd64), const SOCK_CLOEXEC = 268435456 +pkg syscall (freebsd-amd64), const SOCK_CLOEXEC ideal-int +pkg syscall (freebsd-amd64), const SOCK_NONBLOCK = 536870912 +pkg syscall (freebsd-amd64), const SOCK_NONBLOCK ideal-int +pkg syscall (freebsd-amd64), const SO_VENDOR = 2147483648 +pkg syscall (freebsd-amd64), const SO_VENDOR ideal-int +pkg syscall (freebsd-amd64), const SYS_ACCEPT4 = 541 +pkg syscall (freebsd-amd64), const SYS_ACCEPT4 ideal-int +pkg syscall (freebsd-amd64), const SYS_BINDAT = 538 +pkg syscall (freebsd-amd64), const SYS_BINDAT ideal-int +pkg syscall (freebsd-amd64), const SYS_CHFLAGSAT = 540 +pkg syscall (freebsd-amd64), const SYS_CHFLAGSAT ideal-int +pkg syscall (freebsd-amd64), const SYS_CONNECTAT = 539 +pkg syscall (freebsd-amd64), const SYS_CONNECTAT ideal-int +pkg syscall (freebsd-amd64), const SYS_PIPE2 = 542 +pkg syscall (freebsd-amd64), const SYS_PIPE2 ideal-int +pkg syscall (freebsd-amd64), const SYS_PROCCTL = 544 +pkg syscall (freebsd-amd64), const SYS_PROCCTL ideal-int +pkg syscall (freebsd-amd64), const TCP_VENDOR = 2147483648 +pkg syscall (freebsd-amd64), const TCP_VENDOR ideal-int +pkg syscall (freebsd-amd64), const WEXITED = 16 +pkg syscall (freebsd-amd64), const WEXITED ideal-int +pkg syscall (freebsd-amd64), const WTRAPPED = 32 +pkg syscall (freebsd-amd64), const WTRAPPED ideal-int +pkg syscall (freebsd-amd64), func Accept4(int, int) (int, Sockaddr, error) +pkg syscall (freebsd-amd64), func FcntlFlock(uintptr, int, *Flock_t) error +pkg syscall (freebsd-amd64), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error) +pkg syscall (freebsd-amd64), type Termios struct +pkg syscall (freebsd-amd64), type Termios struct, Cc [20]uint8 +pkg syscall (freebsd-amd64), type Termios struct, Cflag uint32 +pkg syscall (freebsd-amd64), type Termios struct, Iflag uint32 +pkg syscall (freebsd-amd64), type Termios struct, Ispeed uint32 +pkg syscall (freebsd-amd64), type Termios struct, Lflag uint32 +pkg syscall (freebsd-amd64), type Termios struct, Oflag uint32 +pkg syscall (freebsd-amd64), type Termios struct, Ospeed uint32 +pkg syscall (freebsd-amd64-cgo), const AF_INET6_SDP = 42 +pkg syscall (freebsd-amd64-cgo), const AF_INET6_SDP ideal-int +pkg syscall (freebsd-amd64-cgo), const AF_INET_SDP = 40 +pkg syscall (freebsd-amd64-cgo), const AF_INET_SDP ideal-int +pkg syscall (freebsd-amd64-cgo), const AF_MAX = 42 +pkg syscall (freebsd-amd64-cgo), const DLT_MATCHING_MAX = 246 +pkg syscall (freebsd-amd64-cgo), const DLT_MPEG_2_TS = 243 +pkg syscall (freebsd-amd64-cgo), const DLT_MPEG_2_TS ideal-int +pkg syscall (freebsd-amd64-cgo), const DLT_NFC_LLCP = 245 +pkg syscall (freebsd-amd64-cgo), const DLT_NFC_LLCP ideal-int +pkg syscall (freebsd-amd64-cgo), const DLT_NG40 = 244 +pkg syscall (freebsd-amd64-cgo), const DLT_NG40 ideal-int +pkg syscall (freebsd-amd64-cgo), const ELAST = 96 +pkg syscall (freebsd-amd64-cgo), const ENOTRECOVERABLE = 95 +pkg syscall (freebsd-amd64-cgo), const ENOTRECOVERABLE Errno +pkg syscall (freebsd-amd64-cgo), const EOWNERDEAD = 96 +pkg syscall (freebsd-amd64-cgo), const EOWNERDEAD Errno +pkg syscall (freebsd-amd64-cgo), const EV_DROP = 4096 +pkg syscall (freebsd-amd64-cgo), const EV_DROP ideal-int +pkg syscall (freebsd-amd64-cgo), const IPPROTO_MPLS = 137 +pkg syscall (freebsd-amd64-cgo), const IPPROTO_MPLS ideal-int +pkg syscall (freebsd-amd64-cgo), const MAP_32BIT = 524288 +pkg syscall (freebsd-amd64-cgo), const MAP_32BIT ideal-int +pkg syscall (freebsd-amd64-cgo), const MAP_ALIGNED_SUPER = 16777216 +pkg syscall (freebsd-amd64-cgo), const MAP_ALIGNED_SUPER ideal-int +pkg syscall (freebsd-amd64-cgo), const MAP_ALIGNMENT_MASK = -16777216 +pkg syscall (freebsd-amd64-cgo), const MAP_ALIGNMENT_MASK ideal-int +pkg syscall (freebsd-amd64-cgo), const MAP_ALIGNMENT_SHIFT = 24 +pkg syscall (freebsd-amd64-cgo), const MAP_ALIGNMENT_SHIFT ideal-int +pkg syscall (freebsd-amd64-cgo), const MSG_CMSG_CLOEXEC = 262144 +pkg syscall (freebsd-amd64-cgo), const MSG_CMSG_CLOEXEC ideal-int +pkg syscall (freebsd-amd64-cgo), const NAME_MAX = 255 +pkg syscall (freebsd-amd64-cgo), const NAME_MAX ideal-int +pkg syscall (freebsd-amd64-cgo), const O_CLOEXEC = 1048576 +pkg syscall (freebsd-amd64-cgo), const RTF_GWFLAG_COMPAT = 2147483648 +pkg syscall (freebsd-amd64-cgo), const RTF_GWFLAG_COMPAT ideal-int +pkg syscall (freebsd-amd64-cgo), const RT_NORTREF = 2 +pkg syscall (freebsd-amd64-cgo), const RT_NORTREF ideal-int +pkg syscall (freebsd-amd64-cgo), const SIGLIBRT = 33 +pkg syscall (freebsd-amd64-cgo), const SIGLIBRT Signal +pkg syscall (freebsd-amd64-cgo), const SOCK_CLOEXEC = 268435456 +pkg syscall (freebsd-amd64-cgo), const SOCK_CLOEXEC ideal-int +pkg syscall (freebsd-amd64-cgo), const SOCK_NONBLOCK = 536870912 +pkg syscall (freebsd-amd64-cgo), const SOCK_NONBLOCK ideal-int +pkg syscall (freebsd-amd64-cgo), const SO_VENDOR = 2147483648 +pkg syscall (freebsd-amd64-cgo), const SO_VENDOR ideal-int +pkg syscall (freebsd-amd64-cgo), const SYS_ACCEPT4 = 541 +pkg syscall (freebsd-amd64-cgo), const SYS_ACCEPT4 ideal-int +pkg syscall (freebsd-amd64-cgo), const SYS_BINDAT = 538 +pkg syscall (freebsd-amd64-cgo), const SYS_BINDAT ideal-int +pkg syscall (freebsd-amd64-cgo), const SYS_CHFLAGSAT = 540 +pkg syscall (freebsd-amd64-cgo), const SYS_CHFLAGSAT ideal-int +pkg syscall (freebsd-amd64-cgo), const SYS_CONNECTAT = 539 +pkg syscall (freebsd-amd64-cgo), const SYS_CONNECTAT ideal-int +pkg syscall (freebsd-amd64-cgo), const SYS_PIPE2 = 542 +pkg syscall (freebsd-amd64-cgo), const SYS_PIPE2 ideal-int +pkg syscall (freebsd-amd64-cgo), const SYS_PROCCTL = 544 +pkg syscall (freebsd-amd64-cgo), const SYS_PROCCTL ideal-int +pkg syscall (freebsd-amd64-cgo), const TCP_VENDOR = 2147483648 +pkg syscall (freebsd-amd64-cgo), const TCP_VENDOR ideal-int +pkg syscall (freebsd-amd64-cgo), const WEXITED = 16 +pkg syscall (freebsd-amd64-cgo), const WEXITED ideal-int +pkg syscall (freebsd-amd64-cgo), const WTRAPPED = 32 +pkg syscall (freebsd-amd64-cgo), const WTRAPPED ideal-int +pkg syscall (freebsd-amd64-cgo), func Accept4(int, int) (int, Sockaddr, error) +pkg syscall (freebsd-amd64-cgo), func FcntlFlock(uintptr, int, *Flock_t) error +pkg syscall (freebsd-amd64-cgo), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error) +pkg syscall (freebsd-amd64-cgo), type Termios struct +pkg syscall (freebsd-amd64-cgo), type Termios struct, Cc [20]uint8 +pkg syscall (freebsd-amd64-cgo), type Termios struct, Cflag uint32 +pkg syscall (freebsd-amd64-cgo), type Termios struct, Iflag uint32 +pkg syscall (freebsd-amd64-cgo), type Termios struct, Ispeed uint32 +pkg syscall (freebsd-amd64-cgo), type Termios struct, Lflag uint32 +pkg syscall (freebsd-amd64-cgo), type Termios struct, Oflag uint32 +pkg syscall (freebsd-amd64-cgo), type Termios struct, Ospeed uint32 +pkg syscall (freebsd-arm), const AF_INET6_SDP = 42 +pkg syscall (freebsd-arm), const AF_INET6_SDP ideal-int +pkg syscall (freebsd-arm), const AF_INET_SDP = 40 +pkg syscall (freebsd-arm), const AF_INET_SDP ideal-int +pkg syscall (freebsd-arm), const AF_MAX = 42 +pkg syscall (freebsd-arm), const BIOCGRTIMEOUT = 1074807406 +pkg syscall (freebsd-arm), const BIOCSRTIMEOUT = 2148549229 +pkg syscall (freebsd-arm), const ELAST = 96 +pkg syscall (freebsd-arm), const ENOTRECOVERABLE = 95 +pkg syscall (freebsd-arm), const ENOTRECOVERABLE Errno +pkg syscall (freebsd-arm), const EOWNERDEAD = 96 +pkg syscall (freebsd-arm), const EOWNERDEAD Errno +pkg syscall (freebsd-arm), const EV_DROP = 4096 +pkg syscall (freebsd-arm), const EV_DROP ideal-int +pkg syscall (freebsd-arm), const IFT_CARP = 248 +pkg syscall (freebsd-arm), const IFT_CARP ideal-int +pkg syscall (freebsd-arm), const MAP_ALIGNED_SUPER = 16777216 +pkg syscall (freebsd-arm), const MAP_ALIGNED_SUPER ideal-int +pkg syscall (freebsd-arm), const MAP_ALIGNMENT_MASK = -16777216 +pkg syscall (freebsd-arm), const MAP_ALIGNMENT_MASK ideal-int +pkg syscall (freebsd-arm), const MAP_ALIGNMENT_SHIFT = 24 +pkg syscall (freebsd-arm), const MAP_ALIGNMENT_SHIFT ideal-int +pkg syscall (freebsd-arm), const MSG_CMSG_CLOEXEC = 262144 +pkg syscall (freebsd-arm), const MSG_CMSG_CLOEXEC ideal-int +pkg syscall (freebsd-arm), const NAME_MAX = 255 +pkg syscall (freebsd-arm), const NAME_MAX ideal-int +pkg syscall (freebsd-arm), const O_CLOEXEC = 1048576 +pkg syscall (freebsd-arm), const RTF_GWFLAG_COMPAT = 2147483648 +pkg syscall (freebsd-arm), const RTF_GWFLAG_COMPAT ideal-int +pkg syscall (freebsd-arm), const SIOCAIFADDR = 2151704858 +pkg syscall (freebsd-arm), const SIOCGIFSTATUS = 3274795323 +pkg syscall (freebsd-arm), const SIOCSIFPHYADDR = 2151704902 +pkg syscall (freebsd-arm), const SOCK_CLOEXEC = 268435456 +pkg syscall (freebsd-arm), const SOCK_CLOEXEC ideal-int +pkg syscall (freebsd-arm), const SOCK_NONBLOCK = 536870912 +pkg syscall (freebsd-arm), const SOCK_NONBLOCK ideal-int +pkg syscall (freebsd-arm), const SO_VENDOR = 2147483648 +pkg syscall (freebsd-arm), const SO_VENDOR ideal-int +pkg syscall (freebsd-arm), const SYS_ACCEPT4 = 541 +pkg syscall (freebsd-arm), const SYS_ACCEPT4 ideal-int +pkg syscall (freebsd-arm), const SYS_BINDAT = 538 +pkg syscall (freebsd-arm), const SYS_BINDAT ideal-int +pkg syscall (freebsd-arm), const SYS_CAP_GETRIGHTS = 515 +pkg syscall (freebsd-arm), const SYS_CAP_GETRIGHTS ideal-int +pkg syscall (freebsd-arm), const SYS_CHFLAGSAT = 540 +pkg syscall (freebsd-arm), const SYS_CHFLAGSAT ideal-int +pkg syscall (freebsd-arm), const SYS_CONNECTAT = 539 +pkg syscall (freebsd-arm), const SYS_CONNECTAT ideal-int +pkg syscall (freebsd-arm), const SYS_PIPE2 = 542 +pkg syscall (freebsd-arm), const SYS_PIPE2 ideal-int +pkg syscall (freebsd-arm), const SYS_PROCCTL = 544 +pkg syscall (freebsd-arm), const SYS_PROCCTL ideal-int +pkg syscall (freebsd-arm), const SizeofBpfHdr = 32 +pkg syscall (freebsd-arm), const SizeofIfData = 96 +pkg syscall (freebsd-arm), const SizeofIfMsghdr = 112 +pkg syscall (freebsd-arm), const SizeofSockaddrDatalink = 54 +pkg syscall (freebsd-arm), const SizeofSockaddrUnix = 106 +pkg syscall (freebsd-arm), const TCP_VENDOR = 2147483648 +pkg syscall (freebsd-arm), const TCP_VENDOR ideal-int +pkg syscall (freebsd-arm), const TIOCTIMESTAMP = 1074820185 +pkg syscall (freebsd-arm), func Accept4(int, int) (int, Sockaddr, error) +pkg syscall (freebsd-arm), func Fchflags(int, int) error +pkg syscall (freebsd-arm), func FcntlFlock(uintptr, int, *Flock_t) error +pkg syscall (freebsd-arm), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error) +pkg syscall (freebsd-arm), type BpfHdr struct, Pad_cgo_0 [6]uint8 +pkg syscall (freebsd-arm), type Flock_t struct, Pad_cgo_0 [4]uint8 +pkg syscall (freebsd-arm), type IfData struct, Pad_cgo_0 [4]uint8 +pkg syscall (freebsd-arm), type Termios struct +pkg syscall (freebsd-arm), type Termios struct, Cc [20]uint8 +pkg syscall (freebsd-arm), type Termios struct, Cflag uint32 +pkg syscall (freebsd-arm), type Termios struct, Iflag uint32 +pkg syscall (freebsd-arm), type Termios struct, Ispeed uint32 +pkg syscall (freebsd-arm), type Termios struct, Lflag uint32 +pkg syscall (freebsd-arm), type Termios struct, Oflag uint32 +pkg syscall (freebsd-arm), type Termios struct, Ospeed uint32 +pkg syscall (freebsd-arm), type Timespec struct, Pad_cgo_0 [4]uint8 +pkg syscall (freebsd-arm), type Timeval struct, Pad_cgo_0 [4]uint8 +pkg syscall (freebsd-arm-cgo), const AF_INET6_SDP = 42 +pkg syscall (freebsd-arm-cgo), const AF_INET6_SDP ideal-int +pkg syscall (freebsd-arm-cgo), const AF_INET_SDP = 40 +pkg syscall (freebsd-arm-cgo), const AF_INET_SDP ideal-int +pkg syscall (freebsd-arm-cgo), const AF_MAX = 42 +pkg syscall (freebsd-arm-cgo), const BIOCGRTIMEOUT = 1074807406 +pkg syscall (freebsd-arm-cgo), const BIOCSRTIMEOUT = 2148549229 +pkg syscall (freebsd-arm-cgo), const ELAST = 96 +pkg syscall (freebsd-arm-cgo), const ENOTRECOVERABLE = 95 +pkg syscall (freebsd-arm-cgo), const ENOTRECOVERABLE Errno +pkg syscall (freebsd-arm-cgo), const EOWNERDEAD = 96 +pkg syscall (freebsd-arm-cgo), const EOWNERDEAD Errno +pkg syscall (freebsd-arm-cgo), const EV_DROP = 4096 +pkg syscall (freebsd-arm-cgo), const EV_DROP ideal-int +pkg syscall (freebsd-arm-cgo), const IFT_CARP = 248 +pkg syscall (freebsd-arm-cgo), const IFT_CARP ideal-int +pkg syscall (freebsd-arm-cgo), const MAP_ALIGNED_SUPER = 16777216 +pkg syscall (freebsd-arm-cgo), const MAP_ALIGNED_SUPER ideal-int +pkg syscall (freebsd-arm-cgo), const MAP_ALIGNMENT_MASK = -16777216 +pkg syscall (freebsd-arm-cgo), const MAP_ALIGNMENT_MASK ideal-int +pkg syscall (freebsd-arm-cgo), const MAP_ALIGNMENT_SHIFT = 24 +pkg syscall (freebsd-arm-cgo), const MAP_ALIGNMENT_SHIFT ideal-int +pkg syscall (freebsd-arm-cgo), const MSG_CMSG_CLOEXEC = 262144 +pkg syscall (freebsd-arm-cgo), const MSG_CMSG_CLOEXEC ideal-int +pkg syscall (freebsd-arm-cgo), const NAME_MAX = 255 +pkg syscall (freebsd-arm-cgo), const NAME_MAX ideal-int +pkg syscall (freebsd-arm-cgo), const O_CLOEXEC = 1048576 +pkg syscall (freebsd-arm-cgo), const RTF_GWFLAG_COMPAT = 2147483648 +pkg syscall (freebsd-arm-cgo), const RTF_GWFLAG_COMPAT ideal-int +pkg syscall (freebsd-arm-cgo), const SIOCAIFADDR = 2151704858 +pkg syscall (freebsd-arm-cgo), const SIOCGIFSTATUS = 3274795323 +pkg syscall (freebsd-arm-cgo), const SIOCSIFPHYADDR = 2151704902 +pkg syscall (freebsd-arm-cgo), const SOCK_CLOEXEC = 268435456 +pkg syscall (freebsd-arm-cgo), const SOCK_CLOEXEC ideal-int +pkg syscall (freebsd-arm-cgo), const SOCK_NONBLOCK = 536870912 +pkg syscall (freebsd-arm-cgo), const SOCK_NONBLOCK ideal-int +pkg syscall (freebsd-arm-cgo), const SO_VENDOR = 2147483648 +pkg syscall (freebsd-arm-cgo), const SO_VENDOR ideal-int +pkg syscall (freebsd-arm-cgo), const SYS_ACCEPT4 = 541 +pkg syscall (freebsd-arm-cgo), const SYS_ACCEPT4 ideal-int +pkg syscall (freebsd-arm-cgo), const SYS_BINDAT = 538 +pkg syscall (freebsd-arm-cgo), const SYS_BINDAT ideal-int +pkg syscall (freebsd-arm-cgo), const SYS_CAP_GETRIGHTS = 515 +pkg syscall (freebsd-arm-cgo), const SYS_CAP_GETRIGHTS ideal-int +pkg syscall (freebsd-arm-cgo), const SYS_CHFLAGSAT = 540 +pkg syscall (freebsd-arm-cgo), const SYS_CHFLAGSAT ideal-int +pkg syscall (freebsd-arm-cgo), const SYS_CONNECTAT = 539 +pkg syscall (freebsd-arm-cgo), const SYS_CONNECTAT ideal-int +pkg syscall (freebsd-arm-cgo), const SYS_PIPE2 = 542 +pkg syscall (freebsd-arm-cgo), const SYS_PIPE2 ideal-int +pkg syscall (freebsd-arm-cgo), const SYS_PROCCTL = 544 +pkg syscall (freebsd-arm-cgo), const SYS_PROCCTL ideal-int +pkg syscall (freebsd-arm-cgo), const SizeofBpfHdr = 32 +pkg syscall (freebsd-arm-cgo), const SizeofIfData = 96 +pkg syscall (freebsd-arm-cgo), const SizeofIfMsghdr = 112 +pkg syscall (freebsd-arm-cgo), const SizeofSockaddrDatalink = 54 +pkg syscall (freebsd-arm-cgo), const SizeofSockaddrUnix = 106 +pkg syscall (freebsd-arm-cgo), const TCP_VENDOR = 2147483648 +pkg syscall (freebsd-arm-cgo), const TCP_VENDOR ideal-int +pkg syscall (freebsd-arm-cgo), const TIOCTIMESTAMP = 1074820185 +pkg syscall (freebsd-arm-cgo), func Accept4(int, int) (int, Sockaddr, error) +pkg syscall (freebsd-arm-cgo), func Fchflags(int, int) error +pkg syscall (freebsd-arm-cgo), func FcntlFlock(uintptr, int, *Flock_t) error +pkg syscall (freebsd-arm-cgo), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error) +pkg syscall (freebsd-arm-cgo), type BpfHdr struct, Pad_cgo_0 [6]uint8 +pkg syscall (freebsd-arm-cgo), type Flock_t struct, Pad_cgo_0 [4]uint8 +pkg syscall (freebsd-arm-cgo), type IfData struct, Pad_cgo_0 [4]uint8 +pkg syscall (freebsd-arm-cgo), type Termios struct +pkg syscall (freebsd-arm-cgo), type Termios struct, Cc [20]uint8 +pkg syscall (freebsd-arm-cgo), type Termios struct, Cflag uint32 +pkg syscall (freebsd-arm-cgo), type Termios struct, Iflag uint32 +pkg syscall (freebsd-arm-cgo), type Termios struct, Ispeed uint32 +pkg syscall (freebsd-arm-cgo), type Termios struct, Lflag uint32 +pkg syscall (freebsd-arm-cgo), type Termios struct, Oflag uint32 +pkg syscall (freebsd-arm-cgo), type Termios struct, Ospeed uint32 +pkg syscall (freebsd-arm-cgo), type Timespec struct, Pad_cgo_0 [4]uint8 +pkg syscall (freebsd-arm-cgo), type Timeval struct, Pad_cgo_0 [4]uint8 +pkg syscall (linux-386), func FcntlFlock(uintptr, int, *Flock_t) error +pkg syscall (linux-386), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error) +pkg syscall (linux-386), type Flock_t struct +pkg syscall (linux-386), type Flock_t struct, Len int64 +pkg syscall (linux-386), type Flock_t struct, Pid int32 +pkg syscall (linux-386), type Flock_t struct, Start int64 +pkg syscall (linux-386), type Flock_t struct, Type int16 +pkg syscall (linux-386), type Flock_t struct, Whence int16 +pkg syscall (linux-386-cgo), func FcntlFlock(uintptr, int, *Flock_t) error +pkg syscall (linux-386-cgo), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error) +pkg syscall (linux-386-cgo), type Flock_t struct +pkg syscall (linux-386-cgo), type Flock_t struct, Len int64 +pkg syscall (linux-386-cgo), type Flock_t struct, Pid int32 +pkg syscall (linux-386-cgo), type Flock_t struct, Start int64 +pkg syscall (linux-386-cgo), type Flock_t struct, Type int16 +pkg syscall (linux-386-cgo), type Flock_t struct, Whence int16 +pkg syscall (linux-amd64), func FcntlFlock(uintptr, int, *Flock_t) error +pkg syscall (linux-amd64), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error) +pkg syscall (linux-amd64), type Flock_t struct +pkg syscall (linux-amd64), type Flock_t struct, Len int64 +pkg syscall (linux-amd64), type Flock_t struct, Pad_cgo_0 [4]uint8 +pkg syscall (linux-amd64), type Flock_t struct, Pad_cgo_1 [4]uint8 +pkg syscall (linux-amd64), type Flock_t struct, Pid int32 +pkg syscall (linux-amd64), type Flock_t struct, Start int64 +pkg syscall (linux-amd64), type Flock_t struct, Type int16 +pkg syscall (linux-amd64), type Flock_t struct, Whence int16 +pkg syscall (linux-amd64-cgo), func FcntlFlock(uintptr, int, *Flock_t) error +pkg syscall (linux-amd64-cgo), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error) +pkg syscall (linux-amd64-cgo), type Flock_t struct +pkg syscall (linux-amd64-cgo), type Flock_t struct, Len int64 +pkg syscall (linux-amd64-cgo), type Flock_t struct, Pad_cgo_0 [4]uint8 +pkg syscall (linux-amd64-cgo), type Flock_t struct, Pad_cgo_1 [4]uint8 +pkg syscall (linux-amd64-cgo), type Flock_t struct, Pid int32 +pkg syscall (linux-amd64-cgo), type Flock_t struct, Start int64 +pkg syscall (linux-amd64-cgo), type Flock_t struct, Type int16 +pkg syscall (linux-amd64-cgo), type Flock_t struct, Whence int16 +pkg syscall (linux-arm), func FcntlFlock(uintptr, int, *Flock_t) error +pkg syscall (linux-arm), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error) +pkg syscall (linux-arm), type Flock_t struct +pkg syscall (linux-arm), type Flock_t struct, Len int64 +pkg syscall (linux-arm), type Flock_t struct, Pad_cgo_0 [4]uint8 +pkg syscall (linux-arm), type Flock_t struct, Pad_cgo_1 [4]uint8 +pkg syscall (linux-arm), type Flock_t struct, Pid int32 +pkg syscall (linux-arm), type Flock_t struct, Start int64 +pkg syscall (linux-arm), type Flock_t struct, Type int16 +pkg syscall (linux-arm), type Flock_t struct, Whence int16 +pkg syscall (linux-arm-cgo), func FcntlFlock(uintptr, int, *Flock_t) error +pkg syscall (linux-arm-cgo), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error) +pkg syscall (linux-arm-cgo), type Flock_t struct +pkg syscall (linux-arm-cgo), type Flock_t struct, Len int64 +pkg syscall (linux-arm-cgo), type Flock_t struct, Pad_cgo_0 [4]uint8 +pkg syscall (linux-arm-cgo), type Flock_t struct, Pad_cgo_1 [4]uint8 +pkg syscall (linux-arm-cgo), type Flock_t struct, Pid int32 +pkg syscall (linux-arm-cgo), type Flock_t struct, Start int64 +pkg syscall (linux-arm-cgo), type Flock_t struct, Type int16 +pkg syscall (linux-arm-cgo), type Flock_t struct, Whence int16 +pkg syscall (netbsd-386), const CLONE_CSIGNAL = 255 +pkg syscall (netbsd-386), const CLONE_CSIGNAL ideal-int +pkg syscall (netbsd-386), const CLONE_FILES = 1024 +pkg syscall (netbsd-386), const CLONE_FILES ideal-int +pkg syscall (netbsd-386), const CLONE_FS = 512 +pkg syscall (netbsd-386), const CLONE_FS ideal-int +pkg syscall (netbsd-386), const CLONE_PID = 4096 +pkg syscall (netbsd-386), const CLONE_PID ideal-int +pkg syscall (netbsd-386), const CLONE_PTRACE = 8192 +pkg syscall (netbsd-386), const CLONE_PTRACE ideal-int +pkg syscall (netbsd-386), const CLONE_SIGHAND = 2048 +pkg syscall (netbsd-386), const CLONE_SIGHAND ideal-int +pkg syscall (netbsd-386), const CLONE_VFORK = 16384 +pkg syscall (netbsd-386), const CLONE_VFORK ideal-int +pkg syscall (netbsd-386), const CLONE_VM = 256 +pkg syscall (netbsd-386), const CLONE_VM ideal-int +pkg syscall (netbsd-386), const MADV_DONTNEED = 4 +pkg syscall (netbsd-386), const MADV_DONTNEED ideal-int +pkg syscall (netbsd-386), const MADV_FREE = 6 +pkg syscall (netbsd-386), const MADV_FREE ideal-int +pkg syscall (netbsd-386), const MADV_NORMAL = 0 +pkg syscall (netbsd-386), const MADV_NORMAL ideal-int +pkg syscall (netbsd-386), const MADV_RANDOM = 1 +pkg syscall (netbsd-386), const MADV_RANDOM ideal-int +pkg syscall (netbsd-386), const MADV_SEQUENTIAL = 2 +pkg syscall (netbsd-386), const MADV_SEQUENTIAL ideal-int +pkg syscall (netbsd-386), const MADV_SPACEAVAIL = 5 +pkg syscall (netbsd-386), const MADV_SPACEAVAIL ideal-int +pkg syscall (netbsd-386), const MADV_WILLNEED = 3 +pkg syscall (netbsd-386), const MADV_WILLNEED ideal-int +pkg syscall (netbsd-386), const MAP_ALIGNMENT_16MB = 402653184 +pkg syscall (netbsd-386), const MAP_ALIGNMENT_16MB ideal-int +pkg syscall (netbsd-386), const MAP_ALIGNMENT_1TB = 671088640 +pkg syscall (netbsd-386), const MAP_ALIGNMENT_1TB ideal-int +pkg syscall (netbsd-386), const MAP_ALIGNMENT_256TB = 805306368 +pkg syscall (netbsd-386), const MAP_ALIGNMENT_256TB ideal-int +pkg syscall (netbsd-386), const MAP_ALIGNMENT_4GB = 536870912 +pkg syscall (netbsd-386), const MAP_ALIGNMENT_4GB ideal-int +pkg syscall (netbsd-386), const MAP_ALIGNMENT_64KB = 268435456 +pkg syscall (netbsd-386), const MAP_ALIGNMENT_64KB ideal-int +pkg syscall (netbsd-386), const MAP_ALIGNMENT_64PB = 939524096 +pkg syscall (netbsd-386), const MAP_ALIGNMENT_64PB ideal-int +pkg syscall (netbsd-386), const MAP_ALIGNMENT_MASK = -16777216 +pkg syscall (netbsd-386), const MAP_ALIGNMENT_MASK ideal-int +pkg syscall (netbsd-386), const MAP_ALIGNMENT_SHIFT = 24 +pkg syscall (netbsd-386), const MAP_ALIGNMENT_SHIFT ideal-int +pkg syscall (netbsd-386), const MAP_ANON = 4096 +pkg syscall (netbsd-386), const MAP_ANON ideal-int +pkg syscall (netbsd-386), const MAP_FILE = 0 +pkg syscall (netbsd-386), const MAP_FILE ideal-int +pkg syscall (netbsd-386), const MAP_FIXED = 16 +pkg syscall (netbsd-386), const MAP_FIXED ideal-int +pkg syscall (netbsd-386), const MAP_HASSEMAPHORE = 512 +pkg syscall (netbsd-386), const MAP_HASSEMAPHORE ideal-int +pkg syscall (netbsd-386), const MAP_INHERIT = 128 +pkg syscall (netbsd-386), const MAP_INHERIT ideal-int +pkg syscall (netbsd-386), const MAP_INHERIT_COPY = 1 +pkg syscall (netbsd-386), const MAP_INHERIT_COPY ideal-int +pkg syscall (netbsd-386), const MAP_INHERIT_DEFAULT = 1 +pkg syscall (netbsd-386), const MAP_INHERIT_DEFAULT ideal-int +pkg syscall (netbsd-386), const MAP_INHERIT_DONATE_COPY = 3 +pkg syscall (netbsd-386), const MAP_INHERIT_DONATE_COPY ideal-int +pkg syscall (netbsd-386), const MAP_INHERIT_NONE = 2 +pkg syscall (netbsd-386), const MAP_INHERIT_NONE ideal-int +pkg syscall (netbsd-386), const MAP_INHERIT_SHARE = 0 +pkg syscall (netbsd-386), const MAP_INHERIT_SHARE ideal-int +pkg syscall (netbsd-386), const MAP_NORESERVE = 64 +pkg syscall (netbsd-386), const MAP_NORESERVE ideal-int +pkg syscall (netbsd-386), const MAP_PRIVATE = 2 +pkg syscall (netbsd-386), const MAP_PRIVATE ideal-int +pkg syscall (netbsd-386), const MAP_RENAME = 32 +pkg syscall (netbsd-386), const MAP_RENAME ideal-int +pkg syscall (netbsd-386), const MAP_SHARED = 1 +pkg syscall (netbsd-386), const MAP_SHARED ideal-int +pkg syscall (netbsd-386), const MAP_STACK = 8192 +pkg syscall (netbsd-386), const MAP_STACK ideal-int +pkg syscall (netbsd-386), const MAP_TRYFIXED = 1024 +pkg syscall (netbsd-386), const MAP_TRYFIXED ideal-int +pkg syscall (netbsd-386), const MAP_WIRED = 2048 +pkg syscall (netbsd-386), const MAP_WIRED ideal-int +pkg syscall (netbsd-386), const MCL_CURRENT = 1 +pkg syscall (netbsd-386), const MCL_CURRENT ideal-int +pkg syscall (netbsd-386), const MCL_FUTURE = 2 +pkg syscall (netbsd-386), const MCL_FUTURE ideal-int +pkg syscall (netbsd-386), const MS_ASYNC = 1 +pkg syscall (netbsd-386), const MS_ASYNC ideal-int +pkg syscall (netbsd-386), const MS_INVALIDATE = 2 +pkg syscall (netbsd-386), const MS_INVALIDATE ideal-int +pkg syscall (netbsd-386), const MS_SYNC = 4 +pkg syscall (netbsd-386), const MS_SYNC ideal-int +pkg syscall (netbsd-386), const PROT_EXEC = 4 +pkg syscall (netbsd-386), const PROT_EXEC ideal-int +pkg syscall (netbsd-386), const PROT_NONE = 0 +pkg syscall (netbsd-386), const PROT_NONE ideal-int +pkg syscall (netbsd-386), const PROT_READ = 1 +pkg syscall (netbsd-386), const PROT_READ ideal-int +pkg syscall (netbsd-386), const PROT_WRITE = 2 +pkg syscall (netbsd-386), const PROT_WRITE ideal-int +pkg syscall (netbsd-386), func FcntlFlock(uintptr, int, *Flock_t) error +pkg syscall (netbsd-386), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error) +pkg syscall (netbsd-386), type Termios struct +pkg syscall (netbsd-386), type Termios struct, Cc [20]uint8 +pkg syscall (netbsd-386), type Termios struct, Cflag uint32 +pkg syscall (netbsd-386), type Termios struct, Iflag uint32 +pkg syscall (netbsd-386), type Termios struct, Ispeed int32 +pkg syscall (netbsd-386), type Termios struct, Lflag uint32 +pkg syscall (netbsd-386), type Termios struct, Oflag uint32 +pkg syscall (netbsd-386), type Termios struct, Ospeed int32 +pkg syscall (netbsd-386-cgo), const CLONE_CSIGNAL = 255 +pkg syscall (netbsd-386-cgo), const CLONE_CSIGNAL ideal-int +pkg syscall (netbsd-386-cgo), const CLONE_FILES = 1024 +pkg syscall (netbsd-386-cgo), const CLONE_FILES ideal-int +pkg syscall (netbsd-386-cgo), const CLONE_FS = 512 +pkg syscall (netbsd-386-cgo), const CLONE_FS ideal-int +pkg syscall (netbsd-386-cgo), const CLONE_PID = 4096 +pkg syscall (netbsd-386-cgo), const CLONE_PID ideal-int +pkg syscall (netbsd-386-cgo), const CLONE_PTRACE = 8192 +pkg syscall (netbsd-386-cgo), const CLONE_PTRACE ideal-int +pkg syscall (netbsd-386-cgo), const CLONE_SIGHAND = 2048 +pkg syscall (netbsd-386-cgo), const CLONE_SIGHAND ideal-int +pkg syscall (netbsd-386-cgo), const CLONE_VFORK = 16384 +pkg syscall (netbsd-386-cgo), const CLONE_VFORK ideal-int +pkg syscall (netbsd-386-cgo), const CLONE_VM = 256 +pkg syscall (netbsd-386-cgo), const CLONE_VM ideal-int +pkg syscall (netbsd-386-cgo), const MADV_DONTNEED = 4 +pkg syscall (netbsd-386-cgo), const MADV_DONTNEED ideal-int +pkg syscall (netbsd-386-cgo), const MADV_FREE = 6 +pkg syscall (netbsd-386-cgo), const MADV_FREE ideal-int +pkg syscall (netbsd-386-cgo), const MADV_NORMAL = 0 +pkg syscall (netbsd-386-cgo), const MADV_NORMAL ideal-int +pkg syscall (netbsd-386-cgo), const MADV_RANDOM = 1 +pkg syscall (netbsd-386-cgo), const MADV_RANDOM ideal-int +pkg syscall (netbsd-386-cgo), const MADV_SEQUENTIAL = 2 +pkg syscall (netbsd-386-cgo), const MADV_SEQUENTIAL ideal-int +pkg syscall (netbsd-386-cgo), const MADV_SPACEAVAIL = 5 +pkg syscall (netbsd-386-cgo), const MADV_SPACEAVAIL ideal-int +pkg syscall (netbsd-386-cgo), const MADV_WILLNEED = 3 +pkg syscall (netbsd-386-cgo), const MADV_WILLNEED ideal-int +pkg syscall (netbsd-386-cgo), const MAP_ALIGNMENT_16MB = 402653184 +pkg syscall (netbsd-386-cgo), const MAP_ALIGNMENT_16MB ideal-int +pkg syscall (netbsd-386-cgo), const MAP_ALIGNMENT_1TB = 671088640 +pkg syscall (netbsd-386-cgo), const MAP_ALIGNMENT_1TB ideal-int +pkg syscall (netbsd-386-cgo), const MAP_ALIGNMENT_256TB = 805306368 +pkg syscall (netbsd-386-cgo), const MAP_ALIGNMENT_256TB ideal-int +pkg syscall (netbsd-386-cgo), const MAP_ALIGNMENT_4GB = 536870912 +pkg syscall (netbsd-386-cgo), const MAP_ALIGNMENT_4GB ideal-int +pkg syscall (netbsd-386-cgo), const MAP_ALIGNMENT_64KB = 268435456 +pkg syscall (netbsd-386-cgo), const MAP_ALIGNMENT_64KB ideal-int +pkg syscall (netbsd-386-cgo), const MAP_ALIGNMENT_64PB = 939524096 +pkg syscall (netbsd-386-cgo), const MAP_ALIGNMENT_64PB ideal-int +pkg syscall (netbsd-386-cgo), const MAP_ALIGNMENT_MASK = -16777216 +pkg syscall (netbsd-386-cgo), const MAP_ALIGNMENT_MASK ideal-int +pkg syscall (netbsd-386-cgo), const MAP_ALIGNMENT_SHIFT = 24 +pkg syscall (netbsd-386-cgo), const MAP_ALIGNMENT_SHIFT ideal-int +pkg syscall (netbsd-386-cgo), const MAP_ANON = 4096 +pkg syscall (netbsd-386-cgo), const MAP_ANON ideal-int +pkg syscall (netbsd-386-cgo), const MAP_FILE = 0 +pkg syscall (netbsd-386-cgo), const MAP_FILE ideal-int +pkg syscall (netbsd-386-cgo), const MAP_FIXED = 16 +pkg syscall (netbsd-386-cgo), const MAP_FIXED ideal-int +pkg syscall (netbsd-386-cgo), const MAP_HASSEMAPHORE = 512 +pkg syscall (netbsd-386-cgo), const MAP_HASSEMAPHORE ideal-int +pkg syscall (netbsd-386-cgo), const MAP_INHERIT = 128 +pkg syscall (netbsd-386-cgo), const MAP_INHERIT ideal-int +pkg syscall (netbsd-386-cgo), const MAP_INHERIT_COPY = 1 +pkg syscall (netbsd-386-cgo), const MAP_INHERIT_COPY ideal-int +pkg syscall (netbsd-386-cgo), const MAP_INHERIT_DEFAULT = 1 +pkg syscall (netbsd-386-cgo), const MAP_INHERIT_DEFAULT ideal-int +pkg syscall (netbsd-386-cgo), const MAP_INHERIT_DONATE_COPY = 3 +pkg syscall (netbsd-386-cgo), const MAP_INHERIT_DONATE_COPY ideal-int +pkg syscall (netbsd-386-cgo), const MAP_INHERIT_NONE = 2 +pkg syscall (netbsd-386-cgo), const MAP_INHERIT_NONE ideal-int +pkg syscall (netbsd-386-cgo), const MAP_INHERIT_SHARE = 0 +pkg syscall (netbsd-386-cgo), const MAP_INHERIT_SHARE ideal-int +pkg syscall (netbsd-386-cgo), const MAP_NORESERVE = 64 +pkg syscall (netbsd-386-cgo), const MAP_NORESERVE ideal-int +pkg syscall (netbsd-386-cgo), const MAP_PRIVATE = 2 +pkg syscall (netbsd-386-cgo), const MAP_PRIVATE ideal-int +pkg syscall (netbsd-386-cgo), const MAP_RENAME = 32 +pkg syscall (netbsd-386-cgo), const MAP_RENAME ideal-int +pkg syscall (netbsd-386-cgo), const MAP_SHARED = 1 +pkg syscall (netbsd-386-cgo), const MAP_SHARED ideal-int +pkg syscall (netbsd-386-cgo), const MAP_STACK = 8192 +pkg syscall (netbsd-386-cgo), const MAP_STACK ideal-int +pkg syscall (netbsd-386-cgo), const MAP_TRYFIXED = 1024 +pkg syscall (netbsd-386-cgo), const MAP_TRYFIXED ideal-int +pkg syscall (netbsd-386-cgo), const MAP_WIRED = 2048 +pkg syscall (netbsd-386-cgo), const MAP_WIRED ideal-int +pkg syscall (netbsd-386-cgo), const MCL_CURRENT = 1 +pkg syscall (netbsd-386-cgo), const MCL_CURRENT ideal-int +pkg syscall (netbsd-386-cgo), const MCL_FUTURE = 2 +pkg syscall (netbsd-386-cgo), const MCL_FUTURE ideal-int +pkg syscall (netbsd-386-cgo), const MS_ASYNC = 1 +pkg syscall (netbsd-386-cgo), const MS_ASYNC ideal-int +pkg syscall (netbsd-386-cgo), const MS_INVALIDATE = 2 +pkg syscall (netbsd-386-cgo), const MS_INVALIDATE ideal-int +pkg syscall (netbsd-386-cgo), const MS_SYNC = 4 +pkg syscall (netbsd-386-cgo), const MS_SYNC ideal-int +pkg syscall (netbsd-386-cgo), const PROT_EXEC = 4 +pkg syscall (netbsd-386-cgo), const PROT_EXEC ideal-int +pkg syscall (netbsd-386-cgo), const PROT_NONE = 0 +pkg syscall (netbsd-386-cgo), const PROT_NONE ideal-int +pkg syscall (netbsd-386-cgo), const PROT_READ = 1 +pkg syscall (netbsd-386-cgo), const PROT_READ ideal-int +pkg syscall (netbsd-386-cgo), const PROT_WRITE = 2 +pkg syscall (netbsd-386-cgo), const PROT_WRITE ideal-int +pkg syscall (netbsd-386-cgo), func FcntlFlock(uintptr, int, *Flock_t) error +pkg syscall (netbsd-386-cgo), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error) +pkg syscall (netbsd-386-cgo), type Termios struct +pkg syscall (netbsd-386-cgo), type Termios struct, Cc [20]uint8 +pkg syscall (netbsd-386-cgo), type Termios struct, Cflag uint32 +pkg syscall (netbsd-386-cgo), type Termios struct, Iflag uint32 +pkg syscall (netbsd-386-cgo), type Termios struct, Ispeed int32 +pkg syscall (netbsd-386-cgo), type Termios struct, Lflag uint32 +pkg syscall (netbsd-386-cgo), type Termios struct, Oflag uint32 +pkg syscall (netbsd-386-cgo), type Termios struct, Ospeed int32 +pkg syscall (netbsd-amd64), const CLONE_CSIGNAL = 255 +pkg syscall (netbsd-amd64), const CLONE_CSIGNAL ideal-int +pkg syscall (netbsd-amd64), const CLONE_FILES = 1024 +pkg syscall (netbsd-amd64), const CLONE_FILES ideal-int +pkg syscall (netbsd-amd64), const CLONE_FS = 512 +pkg syscall (netbsd-amd64), const CLONE_FS ideal-int +pkg syscall (netbsd-amd64), const CLONE_PID = 4096 +pkg syscall (netbsd-amd64), const CLONE_PID ideal-int +pkg syscall (netbsd-amd64), const CLONE_PTRACE = 8192 +pkg syscall (netbsd-amd64), const CLONE_PTRACE ideal-int +pkg syscall (netbsd-amd64), const CLONE_SIGHAND = 2048 +pkg syscall (netbsd-amd64), const CLONE_SIGHAND ideal-int +pkg syscall (netbsd-amd64), const CLONE_VFORK = 16384 +pkg syscall (netbsd-amd64), const CLONE_VFORK ideal-int +pkg syscall (netbsd-amd64), const CLONE_VM = 256 +pkg syscall (netbsd-amd64), const CLONE_VM ideal-int +pkg syscall (netbsd-amd64), const MADV_DONTNEED = 4 +pkg syscall (netbsd-amd64), const MADV_DONTNEED ideal-int +pkg syscall (netbsd-amd64), const MADV_FREE = 6 +pkg syscall (netbsd-amd64), const MADV_FREE ideal-int +pkg syscall (netbsd-amd64), const MADV_NORMAL = 0 +pkg syscall (netbsd-amd64), const MADV_NORMAL ideal-int +pkg syscall (netbsd-amd64), const MADV_RANDOM = 1 +pkg syscall (netbsd-amd64), const MADV_RANDOM ideal-int +pkg syscall (netbsd-amd64), const MADV_SEQUENTIAL = 2 +pkg syscall (netbsd-amd64), const MADV_SEQUENTIAL ideal-int +pkg syscall (netbsd-amd64), const MADV_SPACEAVAIL = 5 +pkg syscall (netbsd-amd64), const MADV_SPACEAVAIL ideal-int +pkg syscall (netbsd-amd64), const MADV_WILLNEED = 3 +pkg syscall (netbsd-amd64), const MADV_WILLNEED ideal-int +pkg syscall (netbsd-amd64), const MAP_ALIGNMENT_16MB = 402653184 +pkg syscall (netbsd-amd64), const MAP_ALIGNMENT_16MB ideal-int +pkg syscall (netbsd-amd64), const MAP_ALIGNMENT_1TB = 671088640 +pkg syscall (netbsd-amd64), const MAP_ALIGNMENT_1TB ideal-int +pkg syscall (netbsd-amd64), const MAP_ALIGNMENT_256TB = 805306368 +pkg syscall (netbsd-amd64), const MAP_ALIGNMENT_256TB ideal-int +pkg syscall (netbsd-amd64), const MAP_ALIGNMENT_4GB = 536870912 +pkg syscall (netbsd-amd64), const MAP_ALIGNMENT_4GB ideal-int +pkg syscall (netbsd-amd64), const MAP_ALIGNMENT_64KB = 268435456 +pkg syscall (netbsd-amd64), const MAP_ALIGNMENT_64KB ideal-int +pkg syscall (netbsd-amd64), const MAP_ALIGNMENT_64PB = 939524096 +pkg syscall (netbsd-amd64), const MAP_ALIGNMENT_64PB ideal-int +pkg syscall (netbsd-amd64), const MAP_ALIGNMENT_MASK = -16777216 +pkg syscall (netbsd-amd64), const MAP_ALIGNMENT_MASK ideal-int +pkg syscall (netbsd-amd64), const MAP_ALIGNMENT_SHIFT = 24 +pkg syscall (netbsd-amd64), const MAP_ALIGNMENT_SHIFT ideal-int +pkg syscall (netbsd-amd64), const MAP_ANON = 4096 +pkg syscall (netbsd-amd64), const MAP_ANON ideal-int +pkg syscall (netbsd-amd64), const MAP_FILE = 0 +pkg syscall (netbsd-amd64), const MAP_FILE ideal-int +pkg syscall (netbsd-amd64), const MAP_FIXED = 16 +pkg syscall (netbsd-amd64), const MAP_FIXED ideal-int +pkg syscall (netbsd-amd64), const MAP_HASSEMAPHORE = 512 +pkg syscall (netbsd-amd64), const MAP_HASSEMAPHORE ideal-int +pkg syscall (netbsd-amd64), const MAP_INHERIT = 128 +pkg syscall (netbsd-amd64), const MAP_INHERIT ideal-int +pkg syscall (netbsd-amd64), const MAP_INHERIT_COPY = 1 +pkg syscall (netbsd-amd64), const MAP_INHERIT_COPY ideal-int +pkg syscall (netbsd-amd64), const MAP_INHERIT_DEFAULT = 1 +pkg syscall (netbsd-amd64), const MAP_INHERIT_DEFAULT ideal-int +pkg syscall (netbsd-amd64), const MAP_INHERIT_DONATE_COPY = 3 +pkg syscall (netbsd-amd64), const MAP_INHERIT_DONATE_COPY ideal-int +pkg syscall (netbsd-amd64), const MAP_INHERIT_NONE = 2 +pkg syscall (netbsd-amd64), const MAP_INHERIT_NONE ideal-int +pkg syscall (netbsd-amd64), const MAP_INHERIT_SHARE = 0 +pkg syscall (netbsd-amd64), const MAP_INHERIT_SHARE ideal-int +pkg syscall (netbsd-amd64), const MAP_NORESERVE = 64 +pkg syscall (netbsd-amd64), const MAP_NORESERVE ideal-int +pkg syscall (netbsd-amd64), const MAP_PRIVATE = 2 +pkg syscall (netbsd-amd64), const MAP_PRIVATE ideal-int +pkg syscall (netbsd-amd64), const MAP_RENAME = 32 +pkg syscall (netbsd-amd64), const MAP_RENAME ideal-int +pkg syscall (netbsd-amd64), const MAP_SHARED = 1 +pkg syscall (netbsd-amd64), const MAP_SHARED ideal-int +pkg syscall (netbsd-amd64), const MAP_STACK = 8192 +pkg syscall (netbsd-amd64), const MAP_STACK ideal-int +pkg syscall (netbsd-amd64), const MAP_TRYFIXED = 1024 +pkg syscall (netbsd-amd64), const MAP_TRYFIXED ideal-int +pkg syscall (netbsd-amd64), const MAP_WIRED = 2048 +pkg syscall (netbsd-amd64), const MAP_WIRED ideal-int +pkg syscall (netbsd-amd64), const MCL_CURRENT = 1 +pkg syscall (netbsd-amd64), const MCL_CURRENT ideal-int +pkg syscall (netbsd-amd64), const MCL_FUTURE = 2 +pkg syscall (netbsd-amd64), const MCL_FUTURE ideal-int +pkg syscall (netbsd-amd64), const MS_ASYNC = 1 +pkg syscall (netbsd-amd64), const MS_ASYNC ideal-int +pkg syscall (netbsd-amd64), const MS_INVALIDATE = 2 +pkg syscall (netbsd-amd64), const MS_INVALIDATE ideal-int +pkg syscall (netbsd-amd64), const MS_SYNC = 4 +pkg syscall (netbsd-amd64), const MS_SYNC ideal-int +pkg syscall (netbsd-amd64), const PROT_EXEC = 4 +pkg syscall (netbsd-amd64), const PROT_EXEC ideal-int +pkg syscall (netbsd-amd64), const PROT_NONE = 0 +pkg syscall (netbsd-amd64), const PROT_NONE ideal-int +pkg syscall (netbsd-amd64), const PROT_READ = 1 +pkg syscall (netbsd-amd64), const PROT_READ ideal-int +pkg syscall (netbsd-amd64), const PROT_WRITE = 2 +pkg syscall (netbsd-amd64), const PROT_WRITE ideal-int +pkg syscall (netbsd-amd64), func FcntlFlock(uintptr, int, *Flock_t) error +pkg syscall (netbsd-amd64), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error) +pkg syscall (netbsd-amd64), type Termios struct +pkg syscall (netbsd-amd64), type Termios struct, Cc [20]uint8 +pkg syscall (netbsd-amd64), type Termios struct, Cflag uint32 +pkg syscall (netbsd-amd64), type Termios struct, Iflag uint32 +pkg syscall (netbsd-amd64), type Termios struct, Ispeed int32 +pkg syscall (netbsd-amd64), type Termios struct, Lflag uint32 +pkg syscall (netbsd-amd64), type Termios struct, Oflag uint32 +pkg syscall (netbsd-amd64), type Termios struct, Ospeed int32 +pkg syscall (netbsd-amd64-cgo), const CLONE_CSIGNAL = 255 +pkg syscall (netbsd-amd64-cgo), const CLONE_CSIGNAL ideal-int +pkg syscall (netbsd-amd64-cgo), const CLONE_FILES = 1024 +pkg syscall (netbsd-amd64-cgo), const CLONE_FILES ideal-int +pkg syscall (netbsd-amd64-cgo), const CLONE_FS = 512 +pkg syscall (netbsd-amd64-cgo), const CLONE_FS ideal-int +pkg syscall (netbsd-amd64-cgo), const CLONE_PID = 4096 +pkg syscall (netbsd-amd64-cgo), const CLONE_PID ideal-int +pkg syscall (netbsd-amd64-cgo), const CLONE_PTRACE = 8192 +pkg syscall (netbsd-amd64-cgo), const CLONE_PTRACE ideal-int +pkg syscall (netbsd-amd64-cgo), const CLONE_SIGHAND = 2048 +pkg syscall (netbsd-amd64-cgo), const CLONE_SIGHAND ideal-int +pkg syscall (netbsd-amd64-cgo), const CLONE_VFORK = 16384 +pkg syscall (netbsd-amd64-cgo), const CLONE_VFORK ideal-int +pkg syscall (netbsd-amd64-cgo), const CLONE_VM = 256 +pkg syscall (netbsd-amd64-cgo), const CLONE_VM ideal-int +pkg syscall (netbsd-amd64-cgo), const MADV_DONTNEED = 4 +pkg syscall (netbsd-amd64-cgo), const MADV_DONTNEED ideal-int +pkg syscall (netbsd-amd64-cgo), const MADV_FREE = 6 +pkg syscall (netbsd-amd64-cgo), const MADV_FREE ideal-int +pkg syscall (netbsd-amd64-cgo), const MADV_NORMAL = 0 +pkg syscall (netbsd-amd64-cgo), const MADV_NORMAL ideal-int +pkg syscall (netbsd-amd64-cgo), const MADV_RANDOM = 1 +pkg syscall (netbsd-amd64-cgo), const MADV_RANDOM ideal-int +pkg syscall (netbsd-amd64-cgo), const MADV_SEQUENTIAL = 2 +pkg syscall (netbsd-amd64-cgo), const MADV_SEQUENTIAL ideal-int +pkg syscall (netbsd-amd64-cgo), const MADV_SPACEAVAIL = 5 +pkg syscall (netbsd-amd64-cgo), const MADV_SPACEAVAIL ideal-int +pkg syscall (netbsd-amd64-cgo), const MADV_WILLNEED = 3 +pkg syscall (netbsd-amd64-cgo), const MADV_WILLNEED ideal-int +pkg syscall (netbsd-amd64-cgo), const MAP_ALIGNMENT_16MB = 402653184 +pkg syscall (netbsd-amd64-cgo), const MAP_ALIGNMENT_16MB ideal-int +pkg syscall (netbsd-amd64-cgo), const MAP_ALIGNMENT_1TB = 671088640 +pkg syscall (netbsd-amd64-cgo), const MAP_ALIGNMENT_1TB ideal-int +pkg syscall (netbsd-amd64-cgo), const MAP_ALIGNMENT_256TB = 805306368 +pkg syscall (netbsd-amd64-cgo), const MAP_ALIGNMENT_256TB ideal-int +pkg syscall (netbsd-amd64-cgo), const MAP_ALIGNMENT_4GB = 536870912 +pkg syscall (netbsd-amd64-cgo), const MAP_ALIGNMENT_4GB ideal-int +pkg syscall (netbsd-amd64-cgo), const MAP_ALIGNMENT_64KB = 268435456 +pkg syscall (netbsd-amd64-cgo), const MAP_ALIGNMENT_64KB ideal-int +pkg syscall (netbsd-amd64-cgo), const MAP_ALIGNMENT_64PB = 939524096 +pkg syscall (netbsd-amd64-cgo), const MAP_ALIGNMENT_64PB ideal-int +pkg syscall (netbsd-amd64-cgo), const MAP_ALIGNMENT_MASK = -16777216 +pkg syscall (netbsd-amd64-cgo), const MAP_ALIGNMENT_MASK ideal-int +pkg syscall (netbsd-amd64-cgo), const MAP_ALIGNMENT_SHIFT = 24 +pkg syscall (netbsd-amd64-cgo), const MAP_ALIGNMENT_SHIFT ideal-int +pkg syscall (netbsd-amd64-cgo), const MAP_ANON = 4096 +pkg syscall (netbsd-amd64-cgo), const MAP_ANON ideal-int +pkg syscall (netbsd-amd64-cgo), const MAP_FILE = 0 +pkg syscall (netbsd-amd64-cgo), const MAP_FILE ideal-int +pkg syscall (netbsd-amd64-cgo), const MAP_FIXED = 16 +pkg syscall (netbsd-amd64-cgo), const MAP_FIXED ideal-int +pkg syscall (netbsd-amd64-cgo), const MAP_HASSEMAPHORE = 512 +pkg syscall (netbsd-amd64-cgo), const MAP_HASSEMAPHORE ideal-int +pkg syscall (netbsd-amd64-cgo), const MAP_INHERIT = 128 +pkg syscall (netbsd-amd64-cgo), const MAP_INHERIT ideal-int +pkg syscall (netbsd-amd64-cgo), const MAP_INHERIT_COPY = 1 +pkg syscall (netbsd-amd64-cgo), const MAP_INHERIT_COPY ideal-int +pkg syscall (netbsd-amd64-cgo), const MAP_INHERIT_DEFAULT = 1 +pkg syscall (netbsd-amd64-cgo), const MAP_INHERIT_DEFAULT ideal-int +pkg syscall (netbsd-amd64-cgo), const MAP_INHERIT_DONATE_COPY = 3 +pkg syscall (netbsd-amd64-cgo), const MAP_INHERIT_DONATE_COPY ideal-int +pkg syscall (netbsd-amd64-cgo), const MAP_INHERIT_NONE = 2 +pkg syscall (netbsd-amd64-cgo), const MAP_INHERIT_NONE ideal-int +pkg syscall (netbsd-amd64-cgo), const MAP_INHERIT_SHARE = 0 +pkg syscall (netbsd-amd64-cgo), const MAP_INHERIT_SHARE ideal-int +pkg syscall (netbsd-amd64-cgo), const MAP_NORESERVE = 64 +pkg syscall (netbsd-amd64-cgo), const MAP_NORESERVE ideal-int +pkg syscall (netbsd-amd64-cgo), const MAP_PRIVATE = 2 +pkg syscall (netbsd-amd64-cgo), const MAP_PRIVATE ideal-int +pkg syscall (netbsd-amd64-cgo), const MAP_RENAME = 32 +pkg syscall (netbsd-amd64-cgo), const MAP_RENAME ideal-int +pkg syscall (netbsd-amd64-cgo), const MAP_SHARED = 1 +pkg syscall (netbsd-amd64-cgo), const MAP_SHARED ideal-int +pkg syscall (netbsd-amd64-cgo), const MAP_STACK = 8192 +pkg syscall (netbsd-amd64-cgo), const MAP_STACK ideal-int +pkg syscall (netbsd-amd64-cgo), const MAP_TRYFIXED = 1024 +pkg syscall (netbsd-amd64-cgo), const MAP_TRYFIXED ideal-int +pkg syscall (netbsd-amd64-cgo), const MAP_WIRED = 2048 +pkg syscall (netbsd-amd64-cgo), const MAP_WIRED ideal-int +pkg syscall (netbsd-amd64-cgo), const MCL_CURRENT = 1 +pkg syscall (netbsd-amd64-cgo), const MCL_CURRENT ideal-int +pkg syscall (netbsd-amd64-cgo), const MCL_FUTURE = 2 +pkg syscall (netbsd-amd64-cgo), const MCL_FUTURE ideal-int +pkg syscall (netbsd-amd64-cgo), const MS_ASYNC = 1 +pkg syscall (netbsd-amd64-cgo), const MS_ASYNC ideal-int +pkg syscall (netbsd-amd64-cgo), const MS_INVALIDATE = 2 +pkg syscall (netbsd-amd64-cgo), const MS_INVALIDATE ideal-int +pkg syscall (netbsd-amd64-cgo), const MS_SYNC = 4 +pkg syscall (netbsd-amd64-cgo), const MS_SYNC ideal-int +pkg syscall (netbsd-amd64-cgo), const PROT_EXEC = 4 +pkg syscall (netbsd-amd64-cgo), const PROT_EXEC ideal-int +pkg syscall (netbsd-amd64-cgo), const PROT_NONE = 0 +pkg syscall (netbsd-amd64-cgo), const PROT_NONE ideal-int +pkg syscall (netbsd-amd64-cgo), const PROT_READ = 1 +pkg syscall (netbsd-amd64-cgo), const PROT_READ ideal-int +pkg syscall (netbsd-amd64-cgo), const PROT_WRITE = 2 +pkg syscall (netbsd-amd64-cgo), const PROT_WRITE ideal-int +pkg syscall (netbsd-amd64-cgo), func FcntlFlock(uintptr, int, *Flock_t) error +pkg syscall (netbsd-amd64-cgo), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error) +pkg syscall (netbsd-amd64-cgo), type Termios struct +pkg syscall (netbsd-amd64-cgo), type Termios struct, Cc [20]uint8 +pkg syscall (netbsd-amd64-cgo), type Termios struct, Cflag uint32 +pkg syscall (netbsd-amd64-cgo), type Termios struct, Iflag uint32 +pkg syscall (netbsd-amd64-cgo), type Termios struct, Ispeed int32 +pkg syscall (netbsd-amd64-cgo), type Termios struct, Lflag uint32 +pkg syscall (netbsd-amd64-cgo), type Termios struct, Oflag uint32 +pkg syscall (netbsd-amd64-cgo), type Termios struct, Ospeed int32 +pkg syscall (netbsd-arm), const MADV_DONTNEED = 4 +pkg syscall (netbsd-arm), const MADV_DONTNEED ideal-int +pkg syscall (netbsd-arm), const MADV_FREE = 6 +pkg syscall (netbsd-arm), const MADV_FREE ideal-int +pkg syscall (netbsd-arm), const MADV_NORMAL = 0 +pkg syscall (netbsd-arm), const MADV_NORMAL ideal-int +pkg syscall (netbsd-arm), const MADV_RANDOM = 1 +pkg syscall (netbsd-arm), const MADV_RANDOM ideal-int +pkg syscall (netbsd-arm), const MADV_SEQUENTIAL = 2 +pkg syscall (netbsd-arm), const MADV_SEQUENTIAL ideal-int +pkg syscall (netbsd-arm), const MADV_SPACEAVAIL = 5 +pkg syscall (netbsd-arm), const MADV_SPACEAVAIL ideal-int +pkg syscall (netbsd-arm), const MADV_WILLNEED = 3 +pkg syscall (netbsd-arm), const MADV_WILLNEED ideal-int +pkg syscall (netbsd-arm), const MAP_ALIGNMENT_16MB = 402653184 +pkg syscall (netbsd-arm), const MAP_ALIGNMENT_16MB ideal-int +pkg syscall (netbsd-arm), const MAP_ALIGNMENT_1TB = 671088640 +pkg syscall (netbsd-arm), const MAP_ALIGNMENT_1TB ideal-int +pkg syscall (netbsd-arm), const MAP_ALIGNMENT_256TB = 805306368 +pkg syscall (netbsd-arm), const MAP_ALIGNMENT_256TB ideal-int +pkg syscall (netbsd-arm), const MAP_ALIGNMENT_4GB = 536870912 +pkg syscall (netbsd-arm), const MAP_ALIGNMENT_4GB ideal-int +pkg syscall (netbsd-arm), const MAP_ALIGNMENT_64KB = 268435456 +pkg syscall (netbsd-arm), const MAP_ALIGNMENT_64KB ideal-int +pkg syscall (netbsd-arm), const MAP_ALIGNMENT_64PB = 939524096 +pkg syscall (netbsd-arm), const MAP_ALIGNMENT_64PB ideal-int +pkg syscall (netbsd-arm), const MAP_ALIGNMENT_MASK = -16777216 +pkg syscall (netbsd-arm), const MAP_ALIGNMENT_MASK ideal-int +pkg syscall (netbsd-arm), const MAP_ALIGNMENT_SHIFT = 24 +pkg syscall (netbsd-arm), const MAP_ALIGNMENT_SHIFT ideal-int +pkg syscall (netbsd-arm), const MAP_ANON = 4096 +pkg syscall (netbsd-arm), const MAP_ANON ideal-int +pkg syscall (netbsd-arm), const MAP_FILE = 0 +pkg syscall (netbsd-arm), const MAP_FILE ideal-int +pkg syscall (netbsd-arm), const MAP_FIXED = 16 +pkg syscall (netbsd-arm), const MAP_FIXED ideal-int +pkg syscall (netbsd-arm), const MAP_HASSEMAPHORE = 512 +pkg syscall (netbsd-arm), const MAP_HASSEMAPHORE ideal-int +pkg syscall (netbsd-arm), const MAP_INHERIT = 128 +pkg syscall (netbsd-arm), const MAP_INHERIT ideal-int +pkg syscall (netbsd-arm), const MAP_INHERIT_COPY = 1 +pkg syscall (netbsd-arm), const MAP_INHERIT_COPY ideal-int +pkg syscall (netbsd-arm), const MAP_INHERIT_DEFAULT = 1 +pkg syscall (netbsd-arm), const MAP_INHERIT_DEFAULT ideal-int +pkg syscall (netbsd-arm), const MAP_INHERIT_DONATE_COPY = 3 +pkg syscall (netbsd-arm), const MAP_INHERIT_DONATE_COPY ideal-int +pkg syscall (netbsd-arm), const MAP_INHERIT_NONE = 2 +pkg syscall (netbsd-arm), const MAP_INHERIT_NONE ideal-int +pkg syscall (netbsd-arm), const MAP_INHERIT_SHARE = 0 +pkg syscall (netbsd-arm), const MAP_INHERIT_SHARE ideal-int +pkg syscall (netbsd-arm), const MAP_NORESERVE = 64 +pkg syscall (netbsd-arm), const MAP_NORESERVE ideal-int +pkg syscall (netbsd-arm), const MAP_PRIVATE = 2 +pkg syscall (netbsd-arm), const MAP_PRIVATE ideal-int +pkg syscall (netbsd-arm), const MAP_RENAME = 32 +pkg syscall (netbsd-arm), const MAP_RENAME ideal-int +pkg syscall (netbsd-arm), const MAP_SHARED = 1 +pkg syscall (netbsd-arm), const MAP_SHARED ideal-int +pkg syscall (netbsd-arm), const MAP_STACK = 8192 +pkg syscall (netbsd-arm), const MAP_STACK ideal-int +pkg syscall (netbsd-arm), const MAP_TRYFIXED = 1024 +pkg syscall (netbsd-arm), const MAP_TRYFIXED ideal-int +pkg syscall (netbsd-arm), const MAP_WIRED = 2048 +pkg syscall (netbsd-arm), const MAP_WIRED ideal-int +pkg syscall (netbsd-arm), const PROT_EXEC = 4 +pkg syscall (netbsd-arm), const PROT_EXEC ideal-int +pkg syscall (netbsd-arm), const PROT_NONE = 0 +pkg syscall (netbsd-arm), const PROT_NONE ideal-int +pkg syscall (netbsd-arm), const PROT_READ = 1 +pkg syscall (netbsd-arm), const PROT_READ ideal-int +pkg syscall (netbsd-arm), const PROT_WRITE = 2 +pkg syscall (netbsd-arm), const PROT_WRITE ideal-int +pkg syscall (netbsd-arm), const SizeofIfData = 136 +pkg syscall (netbsd-arm), func Fchflags(int, int) error +pkg syscall (netbsd-arm), func FcntlFlock(uintptr, int, *Flock_t) error +pkg syscall (netbsd-arm), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error) +pkg syscall (netbsd-arm), type Kevent_t struct, Pad_cgo_0 [4]uint8 +pkg syscall (netbsd-arm), type Stat_t struct, Pad_cgo_0 [4]uint8 +pkg syscall (netbsd-arm), type Stat_t struct, Pad_cgo_1 [4]uint8 +pkg syscall (netbsd-arm), type Stat_t struct, Pad_cgo_2 [4]uint8 +pkg syscall (netbsd-arm), type Termios struct +pkg syscall (netbsd-arm), type Termios struct, Cc [20]uint8 +pkg syscall (netbsd-arm), type Termios struct, Cflag uint32 +pkg syscall (netbsd-arm), type Termios struct, Iflag uint32 +pkg syscall (netbsd-arm), type Termios struct, Ispeed int32 +pkg syscall (netbsd-arm), type Termios struct, Lflag uint32 +pkg syscall (netbsd-arm), type Termios struct, Oflag uint32 +pkg syscall (netbsd-arm), type Termios struct, Ospeed int32 +pkg syscall (netbsd-arm), type Timespec struct, Pad_cgo_0 [4]uint8 +pkg syscall (netbsd-arm), type Timeval struct, Pad_cgo_0 [4]uint8 +pkg syscall (netbsd-arm-cgo), const MADV_DONTNEED = 4 +pkg syscall (netbsd-arm-cgo), const MADV_DONTNEED ideal-int +pkg syscall (netbsd-arm-cgo), const MADV_FREE = 6 +pkg syscall (netbsd-arm-cgo), const MADV_FREE ideal-int +pkg syscall (netbsd-arm-cgo), const MADV_NORMAL = 0 +pkg syscall (netbsd-arm-cgo), const MADV_NORMAL ideal-int +pkg syscall (netbsd-arm-cgo), const MADV_RANDOM = 1 +pkg syscall (netbsd-arm-cgo), const MADV_RANDOM ideal-int +pkg syscall (netbsd-arm-cgo), const MADV_SEQUENTIAL = 2 +pkg syscall (netbsd-arm-cgo), const MADV_SEQUENTIAL ideal-int +pkg syscall (netbsd-arm-cgo), const MADV_SPACEAVAIL = 5 +pkg syscall (netbsd-arm-cgo), const MADV_SPACEAVAIL ideal-int +pkg syscall (netbsd-arm-cgo), const MADV_WILLNEED = 3 +pkg syscall (netbsd-arm-cgo), const MADV_WILLNEED ideal-int +pkg syscall (netbsd-arm-cgo), const MAP_ALIGNMENT_16MB = 402653184 +pkg syscall (netbsd-arm-cgo), const MAP_ALIGNMENT_16MB ideal-int +pkg syscall (netbsd-arm-cgo), const MAP_ALIGNMENT_1TB = 671088640 +pkg syscall (netbsd-arm-cgo), const MAP_ALIGNMENT_1TB ideal-int +pkg syscall (netbsd-arm-cgo), const MAP_ALIGNMENT_256TB = 805306368 +pkg syscall (netbsd-arm-cgo), const MAP_ALIGNMENT_256TB ideal-int +pkg syscall (netbsd-arm-cgo), const MAP_ALIGNMENT_4GB = 536870912 +pkg syscall (netbsd-arm-cgo), const MAP_ALIGNMENT_4GB ideal-int +pkg syscall (netbsd-arm-cgo), const MAP_ALIGNMENT_64KB = 268435456 +pkg syscall (netbsd-arm-cgo), const MAP_ALIGNMENT_64KB ideal-int +pkg syscall (netbsd-arm-cgo), const MAP_ALIGNMENT_64PB = 939524096 +pkg syscall (netbsd-arm-cgo), const MAP_ALIGNMENT_64PB ideal-int +pkg syscall (netbsd-arm-cgo), const MAP_ALIGNMENT_MASK = -16777216 +pkg syscall (netbsd-arm-cgo), const MAP_ALIGNMENT_MASK ideal-int +pkg syscall (netbsd-arm-cgo), const MAP_ALIGNMENT_SHIFT = 24 +pkg syscall (netbsd-arm-cgo), const MAP_ALIGNMENT_SHIFT ideal-int +pkg syscall (netbsd-arm-cgo), const MAP_ANON = 4096 +pkg syscall (netbsd-arm-cgo), const MAP_ANON ideal-int +pkg syscall (netbsd-arm-cgo), const MAP_FILE = 0 +pkg syscall (netbsd-arm-cgo), const MAP_FILE ideal-int +pkg syscall (netbsd-arm-cgo), const MAP_FIXED = 16 +pkg syscall (netbsd-arm-cgo), const MAP_FIXED ideal-int +pkg syscall (netbsd-arm-cgo), const MAP_HASSEMAPHORE = 512 +pkg syscall (netbsd-arm-cgo), const MAP_HASSEMAPHORE ideal-int +pkg syscall (netbsd-arm-cgo), const MAP_INHERIT = 128 +pkg syscall (netbsd-arm-cgo), const MAP_INHERIT ideal-int +pkg syscall (netbsd-arm-cgo), const MAP_INHERIT_COPY = 1 +pkg syscall (netbsd-arm-cgo), const MAP_INHERIT_COPY ideal-int +pkg syscall (netbsd-arm-cgo), const MAP_INHERIT_DEFAULT = 1 +pkg syscall (netbsd-arm-cgo), const MAP_INHERIT_DEFAULT ideal-int +pkg syscall (netbsd-arm-cgo), const MAP_INHERIT_DONATE_COPY = 3 +pkg syscall (netbsd-arm-cgo), const MAP_INHERIT_DONATE_COPY ideal-int +pkg syscall (netbsd-arm-cgo), const MAP_INHERIT_NONE = 2 +pkg syscall (netbsd-arm-cgo), const MAP_INHERIT_NONE ideal-int +pkg syscall (netbsd-arm-cgo), const MAP_INHERIT_SHARE = 0 +pkg syscall (netbsd-arm-cgo), const MAP_INHERIT_SHARE ideal-int +pkg syscall (netbsd-arm-cgo), const MAP_NORESERVE = 64 +pkg syscall (netbsd-arm-cgo), const MAP_NORESERVE ideal-int +pkg syscall (netbsd-arm-cgo), const MAP_PRIVATE = 2 +pkg syscall (netbsd-arm-cgo), const MAP_PRIVATE ideal-int +pkg syscall (netbsd-arm-cgo), const MAP_RENAME = 32 +pkg syscall (netbsd-arm-cgo), const MAP_RENAME ideal-int +pkg syscall (netbsd-arm-cgo), const MAP_SHARED = 1 +pkg syscall (netbsd-arm-cgo), const MAP_SHARED ideal-int +pkg syscall (netbsd-arm-cgo), const MAP_STACK = 8192 +pkg syscall (netbsd-arm-cgo), const MAP_STACK ideal-int +pkg syscall (netbsd-arm-cgo), const MAP_TRYFIXED = 1024 +pkg syscall (netbsd-arm-cgo), const MAP_TRYFIXED ideal-int +pkg syscall (netbsd-arm-cgo), const MAP_WIRED = 2048 +pkg syscall (netbsd-arm-cgo), const MAP_WIRED ideal-int +pkg syscall (netbsd-arm-cgo), const PROT_EXEC = 4 +pkg syscall (netbsd-arm-cgo), const PROT_EXEC ideal-int +pkg syscall (netbsd-arm-cgo), const PROT_NONE = 0 +pkg syscall (netbsd-arm-cgo), const PROT_NONE ideal-int +pkg syscall (netbsd-arm-cgo), const PROT_READ = 1 +pkg syscall (netbsd-arm-cgo), const PROT_READ ideal-int +pkg syscall (netbsd-arm-cgo), const PROT_WRITE = 2 +pkg syscall (netbsd-arm-cgo), const PROT_WRITE ideal-int +pkg syscall (netbsd-arm-cgo), const SizeofIfData = 136 +pkg syscall (netbsd-arm-cgo), func Fchflags(int, int) error +pkg syscall (netbsd-arm-cgo), func FcntlFlock(uintptr, int, *Flock_t) error +pkg syscall (netbsd-arm-cgo), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error) +pkg syscall (netbsd-arm-cgo), type Kevent_t struct, Pad_cgo_0 [4]uint8 +pkg syscall (netbsd-arm-cgo), type Stat_t struct, Pad_cgo_0 [4]uint8 +pkg syscall (netbsd-arm-cgo), type Stat_t struct, Pad_cgo_1 [4]uint8 +pkg syscall (netbsd-arm-cgo), type Stat_t struct, Pad_cgo_2 [4]uint8 +pkg syscall (netbsd-arm-cgo), type Termios struct +pkg syscall (netbsd-arm-cgo), type Termios struct, Cc [20]uint8 +pkg syscall (netbsd-arm-cgo), type Termios struct, Cflag uint32 +pkg syscall (netbsd-arm-cgo), type Termios struct, Iflag uint32 +pkg syscall (netbsd-arm-cgo), type Termios struct, Ispeed int32 +pkg syscall (netbsd-arm-cgo), type Termios struct, Lflag uint32 +pkg syscall (netbsd-arm-cgo), type Termios struct, Oflag uint32 +pkg syscall (netbsd-arm-cgo), type Termios struct, Ospeed int32 +pkg syscall (netbsd-arm-cgo), type Timespec struct, Pad_cgo_0 [4]uint8 +pkg syscall (netbsd-arm-cgo), type Timeval struct, Pad_cgo_0 [4]uint8 +pkg syscall (openbsd-386), const BIOCGRTIMEOUT = 1074545262 +pkg syscall (openbsd-386), const BIOCSRTIMEOUT = 2148287085 +pkg syscall (openbsd-386), const IPPROTO_DIVERT_INIT = 2 +pkg syscall (openbsd-386), const IPPROTO_DIVERT_INIT ideal-int +pkg syscall (openbsd-386), const IPPROTO_DIVERT_RESP = 1 +pkg syscall (openbsd-386), const IPPROTO_DIVERT_RESP ideal-int +pkg syscall (openbsd-386), const IPV6_RECVDSTPORT = 64 +pkg syscall (openbsd-386), const IPV6_RECVDSTPORT ideal-int +pkg syscall (openbsd-386), const IP_DIVERTFL = 4130 +pkg syscall (openbsd-386), const IP_DIVERTFL ideal-int +pkg syscall (openbsd-386), const MADV_DONTNEED = 4 +pkg syscall (openbsd-386), const MADV_DONTNEED ideal-int +pkg syscall (openbsd-386), const MADV_FREE = 6 +pkg syscall (openbsd-386), const MADV_FREE ideal-int +pkg syscall (openbsd-386), const MADV_NORMAL = 0 +pkg syscall (openbsd-386), const MADV_NORMAL ideal-int +pkg syscall (openbsd-386), const MADV_RANDOM = 1 +pkg syscall (openbsd-386), const MADV_RANDOM ideal-int +pkg syscall (openbsd-386), const MADV_SEQUENTIAL = 2 +pkg syscall (openbsd-386), const MADV_SEQUENTIAL ideal-int +pkg syscall (openbsd-386), const MADV_SPACEAVAIL = 5 +pkg syscall (openbsd-386), const MADV_SPACEAVAIL ideal-int +pkg syscall (openbsd-386), const MADV_WILLNEED = 3 +pkg syscall (openbsd-386), const MADV_WILLNEED ideal-int +pkg syscall (openbsd-386), const MAP_ANON = 4096 +pkg syscall (openbsd-386), const MAP_ANON ideal-int +pkg syscall (openbsd-386), const MAP_COPY = 4 +pkg syscall (openbsd-386), const MAP_COPY ideal-int +pkg syscall (openbsd-386), const MAP_FILE = 0 +pkg syscall (openbsd-386), const MAP_FILE ideal-int +pkg syscall (openbsd-386), const MAP_FIXED = 16 +pkg syscall (openbsd-386), const MAP_FIXED ideal-int +pkg syscall (openbsd-386), const MAP_FLAGMASK = 8183 +pkg syscall (openbsd-386), const MAP_FLAGMASK ideal-int +pkg syscall (openbsd-386), const MAP_HASSEMAPHORE = 512 +pkg syscall (openbsd-386), const MAP_HASSEMAPHORE ideal-int +pkg syscall (openbsd-386), const MAP_INHERIT = 128 +pkg syscall (openbsd-386), const MAP_INHERIT ideal-int +pkg syscall (openbsd-386), const MAP_INHERIT_COPY = 1 +pkg syscall (openbsd-386), const MAP_INHERIT_COPY ideal-int +pkg syscall (openbsd-386), const MAP_INHERIT_DONATE_COPY = 3 +pkg syscall (openbsd-386), const MAP_INHERIT_DONATE_COPY ideal-int +pkg syscall (openbsd-386), const MAP_INHERIT_NONE = 2 +pkg syscall (openbsd-386), const MAP_INHERIT_NONE ideal-int +pkg syscall (openbsd-386), const MAP_INHERIT_SHARE = 0 +pkg syscall (openbsd-386), const MAP_INHERIT_SHARE ideal-int +pkg syscall (openbsd-386), const MAP_NOEXTEND = 256 +pkg syscall (openbsd-386), const MAP_NOEXTEND ideal-int +pkg syscall (openbsd-386), const MAP_NORESERVE = 64 +pkg syscall (openbsd-386), const MAP_NORESERVE ideal-int +pkg syscall (openbsd-386), const MAP_PRIVATE = 2 +pkg syscall (openbsd-386), const MAP_PRIVATE ideal-int +pkg syscall (openbsd-386), const MAP_RENAME = 32 +pkg syscall (openbsd-386), const MAP_RENAME ideal-int +pkg syscall (openbsd-386), const MAP_SHARED = 1 +pkg syscall (openbsd-386), const MAP_SHARED ideal-int +pkg syscall (openbsd-386), const MAP_TRYFIXED = 1024 +pkg syscall (openbsd-386), const MAP_TRYFIXED ideal-int +pkg syscall (openbsd-386), const MCL_CURRENT = 1 +pkg syscall (openbsd-386), const MCL_CURRENT ideal-int +pkg syscall (openbsd-386), const MCL_FUTURE = 2 +pkg syscall (openbsd-386), const MCL_FUTURE ideal-int +pkg syscall (openbsd-386), const MS_ASYNC = 1 +pkg syscall (openbsd-386), const MS_ASYNC ideal-int +pkg syscall (openbsd-386), const MS_INVALIDATE = 4 +pkg syscall (openbsd-386), const MS_INVALIDATE ideal-int +pkg syscall (openbsd-386), const MS_SYNC = 2 +pkg syscall (openbsd-386), const MS_SYNC ideal-int +pkg syscall (openbsd-386), const PROT_EXEC = 4 +pkg syscall (openbsd-386), const PROT_EXEC ideal-int +pkg syscall (openbsd-386), const PROT_NONE = 0 +pkg syscall (openbsd-386), const PROT_NONE ideal-int +pkg syscall (openbsd-386), const PROT_READ = 1 +pkg syscall (openbsd-386), const PROT_READ ideal-int +pkg syscall (openbsd-386), const PROT_WRITE = 2 +pkg syscall (openbsd-386), const PROT_WRITE ideal-int +pkg syscall (openbsd-386), const RTF_FMASK = 1112072 +pkg syscall (openbsd-386), const RTM_VERSION = 5 +pkg syscall (openbsd-386), const SIOCBRDGDADDR = 2166909255 +pkg syscall (openbsd-386), const SIOCBRDGGPARAM = 3225184600 +pkg syscall (openbsd-386), const SIOCBRDGSADDR = 3240651076 +pkg syscall (openbsd-386), const SIOCGETVLAN = 3223349648 +pkg syscall (openbsd-386), const SIOCGETVLAN ideal-int +pkg syscall (openbsd-386), const SIOCGIFHARDMTU = 3223349669 +pkg syscall (openbsd-386), const SIOCGIFHARDMTU ideal-int +pkg syscall (openbsd-386), const SIOCGLIFPHYTTL = 3223349673 +pkg syscall (openbsd-386), const SIOCGLIFPHYTTL ideal-int +pkg syscall (openbsd-386), const SIOCGSPPPPARAMS = 3223349652 +pkg syscall (openbsd-386), const SIOCGSPPPPARAMS ideal-int +pkg syscall (openbsd-386), const SIOCGVNETID = 3223349671 +pkg syscall (openbsd-386), const SIOCGVNETID ideal-int +pkg syscall (openbsd-386), const SIOCSETVLAN = 2149607823 +pkg syscall (openbsd-386), const SIOCSETVLAN ideal-int +pkg syscall (openbsd-386), const SIOCSLIFPHYTTL = 2149607848 +pkg syscall (openbsd-386), const SIOCSLIFPHYTTL ideal-int +pkg syscall (openbsd-386), const SIOCSSPPPPARAMS = 2149607827 +pkg syscall (openbsd-386), const SIOCSSPPPPARAMS ideal-int +pkg syscall (openbsd-386), const SIOCSVNETID = 2149607846 +pkg syscall (openbsd-386), const SIOCSVNETID ideal-int +pkg syscall (openbsd-386), const SYS_CLOCK_GETRES = 89 +pkg syscall (openbsd-386), const SYS_CLOCK_GETTIME = 87 +pkg syscall (openbsd-386), const SYS_CLOCK_SETTIME = 88 +pkg syscall (openbsd-386), const SYS_FHSTATFS = 65 +pkg syscall (openbsd-386), const SYS_FSTAT = 53 +pkg syscall (openbsd-386), const SYS_FSTATAT = 42 +pkg syscall (openbsd-386), const SYS_FSTATFS = 64 +pkg syscall (openbsd-386), const SYS_FUTIMENS = 85 +pkg syscall (openbsd-386), const SYS_FUTIMES = 77 +pkg syscall (openbsd-386), const SYS_GETDENTS = 99 +pkg syscall (openbsd-386), const SYS_GETDENTS ideal-int +pkg syscall (openbsd-386), const SYS_GETFSSTAT = 62 +pkg syscall (openbsd-386), const SYS_GETITIMER = 70 +pkg syscall (openbsd-386), const SYS_GETRUSAGE = 19 +pkg syscall (openbsd-386), const SYS_GETTIMEOFDAY = 67 +pkg syscall (openbsd-386), const SYS_KEVENT = 72 +pkg syscall (openbsd-386), const SYS_LSTAT = 40 +pkg syscall (openbsd-386), const SYS_NANOSLEEP = 91 +pkg syscall (openbsd-386), const SYS_PPOLL = 109 +pkg syscall (openbsd-386), const SYS_PPOLL ideal-int +pkg syscall (openbsd-386), const SYS_PSELECT = 110 +pkg syscall (openbsd-386), const SYS_PSELECT ideal-int +pkg syscall (openbsd-386), const SYS_SELECT = 71 +pkg syscall (openbsd-386), const SYS_SETITIMER = 69 +pkg syscall (openbsd-386), const SYS_SETTIMEOFDAY = 68 +pkg syscall (openbsd-386), const SYS_STAT = 38 +pkg syscall (openbsd-386), const SYS_STATFS = 63 +pkg syscall (openbsd-386), const SYS_UTIMENSAT = 84 +pkg syscall (openbsd-386), const SYS_UTIMES = 76 +pkg syscall (openbsd-386), const SYS_UTRACE = 209 +pkg syscall (openbsd-386), const SYS_UTRACE ideal-int +pkg syscall (openbsd-386), const SYS_WAIT4 = 11 +pkg syscall (openbsd-386), const SYS___THRSLEEP = 94 +pkg syscall (openbsd-386), const SizeofIfData = 212 +pkg syscall (openbsd-386), const SizeofIfMsghdr = 236 +pkg syscall (openbsd-386), const SizeofRtMetrics = 56 +pkg syscall (openbsd-386), const SizeofRtMsghdr = 96 +pkg syscall (openbsd-386), const TCP_NOPUSH = 16 +pkg syscall (openbsd-386), const TCP_NOPUSH ideal-int +pkg syscall (openbsd-386), const TIOCGSID = 1074033763 +pkg syscall (openbsd-386), const TIOCGSID ideal-int +pkg syscall (openbsd-386), const TIOCGTSTAMP = 1074558043 +pkg syscall (openbsd-386), func FcntlFlock(uintptr, int, *Flock_t) error +pkg syscall (openbsd-386), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error) +pkg syscall (openbsd-386), type Dirent struct, Fileno uint64 +pkg syscall (openbsd-386), type Dirent struct, Off int64 +pkg syscall (openbsd-386), type Dirent struct, X__d_padding [4]uint8 +pkg syscall (openbsd-386), type FdSet struct, Bits [32]uint32 +pkg syscall (openbsd-386), type Kevent_t struct, Data int64 +pkg syscall (openbsd-386), type Mclpool struct, Grown int32 +pkg syscall (openbsd-386), type RtMetrics struct, Expire int64 +pkg syscall (openbsd-386), type RtMetrics struct, Pad uint32 +pkg syscall (openbsd-386), type Stat_t struct, Ino uint64 +pkg syscall (openbsd-386), type Statfs_t struct, F_ctime uint64 +pkg syscall (openbsd-386), type Statfs_t struct, F_mntfromspec [90]int8 +pkg syscall (openbsd-386), type Statfs_t struct, Pad_cgo_0 [2]uint8 +pkg syscall (openbsd-386), type Termios struct +pkg syscall (openbsd-386), type Termios struct, Cc [20]uint8 +pkg syscall (openbsd-386), type Termios struct, Cflag uint32 +pkg syscall (openbsd-386), type Termios struct, Iflag uint32 +pkg syscall (openbsd-386), type Termios struct, Ispeed int32 +pkg syscall (openbsd-386), type Termios struct, Lflag uint32 +pkg syscall (openbsd-386), type Termios struct, Oflag uint32 +pkg syscall (openbsd-386), type Termios struct, Ospeed int32 +pkg syscall (openbsd-386), type Timespec struct, Sec int64 +pkg syscall (openbsd-386), type Timeval struct, Sec int64 +pkg syscall (openbsd-386-cgo), const BIOCGRTIMEOUT = 1074545262 +pkg syscall (openbsd-386-cgo), const BIOCSRTIMEOUT = 2148287085 +pkg syscall (openbsd-386-cgo), const IPPROTO_DIVERT_INIT = 2 +pkg syscall (openbsd-386-cgo), const IPPROTO_DIVERT_INIT ideal-int +pkg syscall (openbsd-386-cgo), const IPPROTO_DIVERT_RESP = 1 +pkg syscall (openbsd-386-cgo), const IPPROTO_DIVERT_RESP ideal-int +pkg syscall (openbsd-386-cgo), const IPV6_RECVDSTPORT = 64 +pkg syscall (openbsd-386-cgo), const IPV6_RECVDSTPORT ideal-int +pkg syscall (openbsd-386-cgo), const IP_DIVERTFL = 4130 +pkg syscall (openbsd-386-cgo), const IP_DIVERTFL ideal-int +pkg syscall (openbsd-386-cgo), const MADV_DONTNEED = 4 +pkg syscall (openbsd-386-cgo), const MADV_DONTNEED ideal-int +pkg syscall (openbsd-386-cgo), const MADV_FREE = 6 +pkg syscall (openbsd-386-cgo), const MADV_FREE ideal-int +pkg syscall (openbsd-386-cgo), const MADV_NORMAL = 0 +pkg syscall (openbsd-386-cgo), const MADV_NORMAL ideal-int +pkg syscall (openbsd-386-cgo), const MADV_RANDOM = 1 +pkg syscall (openbsd-386-cgo), const MADV_RANDOM ideal-int +pkg syscall (openbsd-386-cgo), const MADV_SEQUENTIAL = 2 +pkg syscall (openbsd-386-cgo), const MADV_SEQUENTIAL ideal-int +pkg syscall (openbsd-386-cgo), const MADV_SPACEAVAIL = 5 +pkg syscall (openbsd-386-cgo), const MADV_SPACEAVAIL ideal-int +pkg syscall (openbsd-386-cgo), const MADV_WILLNEED = 3 +pkg syscall (openbsd-386-cgo), const MADV_WILLNEED ideal-int +pkg syscall (openbsd-386-cgo), const MAP_ANON = 4096 +pkg syscall (openbsd-386-cgo), const MAP_ANON ideal-int +pkg syscall (openbsd-386-cgo), const MAP_COPY = 4 +pkg syscall (openbsd-386-cgo), const MAP_COPY ideal-int +pkg syscall (openbsd-386-cgo), const MAP_FILE = 0 +pkg syscall (openbsd-386-cgo), const MAP_FILE ideal-int +pkg syscall (openbsd-386-cgo), const MAP_FIXED = 16 +pkg syscall (openbsd-386-cgo), const MAP_FIXED ideal-int +pkg syscall (openbsd-386-cgo), const MAP_FLAGMASK = 8183 +pkg syscall (openbsd-386-cgo), const MAP_FLAGMASK ideal-int +pkg syscall (openbsd-386-cgo), const MAP_HASSEMAPHORE = 512 +pkg syscall (openbsd-386-cgo), const MAP_HASSEMAPHORE ideal-int +pkg syscall (openbsd-386-cgo), const MAP_INHERIT = 128 +pkg syscall (openbsd-386-cgo), const MAP_INHERIT ideal-int +pkg syscall (openbsd-386-cgo), const MAP_INHERIT_COPY = 1 +pkg syscall (openbsd-386-cgo), const MAP_INHERIT_COPY ideal-int +pkg syscall (openbsd-386-cgo), const MAP_INHERIT_DONATE_COPY = 3 +pkg syscall (openbsd-386-cgo), const MAP_INHERIT_DONATE_COPY ideal-int +pkg syscall (openbsd-386-cgo), const MAP_INHERIT_NONE = 2 +pkg syscall (openbsd-386-cgo), const MAP_INHERIT_NONE ideal-int +pkg syscall (openbsd-386-cgo), const MAP_INHERIT_SHARE = 0 +pkg syscall (openbsd-386-cgo), const MAP_INHERIT_SHARE ideal-int +pkg syscall (openbsd-386-cgo), const MAP_NOEXTEND = 256 +pkg syscall (openbsd-386-cgo), const MAP_NOEXTEND ideal-int +pkg syscall (openbsd-386-cgo), const MAP_NORESERVE = 64 +pkg syscall (openbsd-386-cgo), const MAP_NORESERVE ideal-int +pkg syscall (openbsd-386-cgo), const MAP_PRIVATE = 2 +pkg syscall (openbsd-386-cgo), const MAP_PRIVATE ideal-int +pkg syscall (openbsd-386-cgo), const MAP_RENAME = 32 +pkg syscall (openbsd-386-cgo), const MAP_RENAME ideal-int +pkg syscall (openbsd-386-cgo), const MAP_SHARED = 1 +pkg syscall (openbsd-386-cgo), const MAP_SHARED ideal-int +pkg syscall (openbsd-386-cgo), const MAP_TRYFIXED = 1024 +pkg syscall (openbsd-386-cgo), const MAP_TRYFIXED ideal-int +pkg syscall (openbsd-386-cgo), const MCL_CURRENT = 1 +pkg syscall (openbsd-386-cgo), const MCL_CURRENT ideal-int +pkg syscall (openbsd-386-cgo), const MCL_FUTURE = 2 +pkg syscall (openbsd-386-cgo), const MCL_FUTURE ideal-int +pkg syscall (openbsd-386-cgo), const MS_ASYNC = 1 +pkg syscall (openbsd-386-cgo), const MS_ASYNC ideal-int +pkg syscall (openbsd-386-cgo), const MS_INVALIDATE = 4 +pkg syscall (openbsd-386-cgo), const MS_INVALIDATE ideal-int +pkg syscall (openbsd-386-cgo), const MS_SYNC = 2 +pkg syscall (openbsd-386-cgo), const MS_SYNC ideal-int +pkg syscall (openbsd-386-cgo), const PROT_EXEC = 4 +pkg syscall (openbsd-386-cgo), const PROT_EXEC ideal-int +pkg syscall (openbsd-386-cgo), const PROT_NONE = 0 +pkg syscall (openbsd-386-cgo), const PROT_NONE ideal-int +pkg syscall (openbsd-386-cgo), const PROT_READ = 1 +pkg syscall (openbsd-386-cgo), const PROT_READ ideal-int +pkg syscall (openbsd-386-cgo), const PROT_WRITE = 2 +pkg syscall (openbsd-386-cgo), const PROT_WRITE ideal-int +pkg syscall (openbsd-386-cgo), const RTF_FMASK = 1112072 +pkg syscall (openbsd-386-cgo), const RTM_VERSION = 5 +pkg syscall (openbsd-386-cgo), const SIOCBRDGDADDR = 2166909255 +pkg syscall (openbsd-386-cgo), const SIOCBRDGGPARAM = 3225184600 +pkg syscall (openbsd-386-cgo), const SIOCBRDGSADDR = 3240651076 +pkg syscall (openbsd-386-cgo), const SIOCGETVLAN = 3223349648 +pkg syscall (openbsd-386-cgo), const SIOCGETVLAN ideal-int +pkg syscall (openbsd-386-cgo), const SIOCGIFHARDMTU = 3223349669 +pkg syscall (openbsd-386-cgo), const SIOCGIFHARDMTU ideal-int +pkg syscall (openbsd-386-cgo), const SIOCGLIFPHYTTL = 3223349673 +pkg syscall (openbsd-386-cgo), const SIOCGLIFPHYTTL ideal-int +pkg syscall (openbsd-386-cgo), const SIOCGSPPPPARAMS = 3223349652 +pkg syscall (openbsd-386-cgo), const SIOCGSPPPPARAMS ideal-int +pkg syscall (openbsd-386-cgo), const SIOCGVNETID = 3223349671 +pkg syscall (openbsd-386-cgo), const SIOCGVNETID ideal-int +pkg syscall (openbsd-386-cgo), const SIOCSETVLAN = 2149607823 +pkg syscall (openbsd-386-cgo), const SIOCSETVLAN ideal-int +pkg syscall (openbsd-386-cgo), const SIOCSLIFPHYTTL = 2149607848 +pkg syscall (openbsd-386-cgo), const SIOCSLIFPHYTTL ideal-int +pkg syscall (openbsd-386-cgo), const SIOCSSPPPPARAMS = 2149607827 +pkg syscall (openbsd-386-cgo), const SIOCSSPPPPARAMS ideal-int +pkg syscall (openbsd-386-cgo), const SIOCSVNETID = 2149607846 +pkg syscall (openbsd-386-cgo), const SIOCSVNETID ideal-int +pkg syscall (openbsd-386-cgo), const SYS_CLOCK_GETRES = 89 +pkg syscall (openbsd-386-cgo), const SYS_CLOCK_GETTIME = 87 +pkg syscall (openbsd-386-cgo), const SYS_CLOCK_SETTIME = 88 +pkg syscall (openbsd-386-cgo), const SYS_FHSTATFS = 65 +pkg syscall (openbsd-386-cgo), const SYS_FSTAT = 53 +pkg syscall (openbsd-386-cgo), const SYS_FSTATAT = 42 +pkg syscall (openbsd-386-cgo), const SYS_FSTATFS = 64 +pkg syscall (openbsd-386-cgo), const SYS_FUTIMENS = 85 +pkg syscall (openbsd-386-cgo), const SYS_FUTIMES = 77 +pkg syscall (openbsd-386-cgo), const SYS_GETDENTS = 99 +pkg syscall (openbsd-386-cgo), const SYS_GETDENTS ideal-int +pkg syscall (openbsd-386-cgo), const SYS_GETFSSTAT = 62 +pkg syscall (openbsd-386-cgo), const SYS_GETITIMER = 70 +pkg syscall (openbsd-386-cgo), const SYS_GETRUSAGE = 19 +pkg syscall (openbsd-386-cgo), const SYS_GETTIMEOFDAY = 67 +pkg syscall (openbsd-386-cgo), const SYS_KEVENT = 72 +pkg syscall (openbsd-386-cgo), const SYS_LSTAT = 40 +pkg syscall (openbsd-386-cgo), const SYS_NANOSLEEP = 91 +pkg syscall (openbsd-386-cgo), const SYS_PPOLL = 109 +pkg syscall (openbsd-386-cgo), const SYS_PPOLL ideal-int +pkg syscall (openbsd-386-cgo), const SYS_PSELECT = 110 +pkg syscall (openbsd-386-cgo), const SYS_PSELECT ideal-int +pkg syscall (openbsd-386-cgo), const SYS_SELECT = 71 +pkg syscall (openbsd-386-cgo), const SYS_SETITIMER = 69 +pkg syscall (openbsd-386-cgo), const SYS_SETTIMEOFDAY = 68 +pkg syscall (openbsd-386-cgo), const SYS_STAT = 38 +pkg syscall (openbsd-386-cgo), const SYS_STATFS = 63 +pkg syscall (openbsd-386-cgo), const SYS_UTIMENSAT = 84 +pkg syscall (openbsd-386-cgo), const SYS_UTIMES = 76 +pkg syscall (openbsd-386-cgo), const SYS_UTRACE = 209 +pkg syscall (openbsd-386-cgo), const SYS_UTRACE ideal-int +pkg syscall (openbsd-386-cgo), const SYS_WAIT4 = 11 +pkg syscall (openbsd-386-cgo), const SYS___THRSLEEP = 94 +pkg syscall (openbsd-386-cgo), const SizeofIfData = 212 +pkg syscall (openbsd-386-cgo), const SizeofIfMsghdr = 236 +pkg syscall (openbsd-386-cgo), const SizeofRtMetrics = 56 +pkg syscall (openbsd-386-cgo), const SizeofRtMsghdr = 96 +pkg syscall (openbsd-386-cgo), const TCP_NOPUSH = 16 +pkg syscall (openbsd-386-cgo), const TCP_NOPUSH ideal-int +pkg syscall (openbsd-386-cgo), const TIOCGSID = 1074033763 +pkg syscall (openbsd-386-cgo), const TIOCGSID ideal-int +pkg syscall (openbsd-386-cgo), const TIOCGTSTAMP = 1074558043 +pkg syscall (openbsd-386-cgo), func FcntlFlock(uintptr, int, *Flock_t) error +pkg syscall (openbsd-386-cgo), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error) +pkg syscall (openbsd-386-cgo), type Dirent struct, Fileno uint64 +pkg syscall (openbsd-386-cgo), type Dirent struct, Off int64 +pkg syscall (openbsd-386-cgo), type Dirent struct, X__d_padding [4]uint8 +pkg syscall (openbsd-386-cgo), type FdSet struct, Bits [32]uint32 +pkg syscall (openbsd-386-cgo), type Kevent_t struct, Data int64 +pkg syscall (openbsd-386-cgo), type Mclpool struct, Grown int32 +pkg syscall (openbsd-386-cgo), type RtMetrics struct, Expire int64 +pkg syscall (openbsd-386-cgo), type RtMetrics struct, Pad uint32 +pkg syscall (openbsd-386-cgo), type Stat_t struct, Ino uint64 +pkg syscall (openbsd-386-cgo), type Statfs_t struct, F_ctime uint64 +pkg syscall (openbsd-386-cgo), type Statfs_t struct, F_mntfromspec [90]int8 +pkg syscall (openbsd-386-cgo), type Statfs_t struct, Pad_cgo_0 [2]uint8 +pkg syscall (openbsd-386-cgo), type Termios struct +pkg syscall (openbsd-386-cgo), type Termios struct, Cc [20]uint8 +pkg syscall (openbsd-386-cgo), type Termios struct, Cflag uint32 +pkg syscall (openbsd-386-cgo), type Termios struct, Iflag uint32 +pkg syscall (openbsd-386-cgo), type Termios struct, Ispeed int32 +pkg syscall (openbsd-386-cgo), type Termios struct, Lflag uint32 +pkg syscall (openbsd-386-cgo), type Termios struct, Oflag uint32 +pkg syscall (openbsd-386-cgo), type Termios struct, Ospeed int32 +pkg syscall (openbsd-386-cgo), type Timespec struct, Sec int64 +pkg syscall (openbsd-386-cgo), type Timeval struct, Sec int64 +pkg syscall (openbsd-amd64), const IPPROTO_DIVERT_INIT = 2 +pkg syscall (openbsd-amd64), const IPPROTO_DIVERT_INIT ideal-int +pkg syscall (openbsd-amd64), const IPPROTO_DIVERT_RESP = 1 +pkg syscall (openbsd-amd64), const IPPROTO_DIVERT_RESP ideal-int +pkg syscall (openbsd-amd64), const IPV6_RECVDSTPORT = 64 +pkg syscall (openbsd-amd64), const IPV6_RECVDSTPORT ideal-int +pkg syscall (openbsd-amd64), const IP_DIVERTFL = 4130 +pkg syscall (openbsd-amd64), const IP_DIVERTFL ideal-int +pkg syscall (openbsd-amd64), const MADV_DONTNEED = 4 +pkg syscall (openbsd-amd64), const MADV_DONTNEED ideal-int +pkg syscall (openbsd-amd64), const MADV_FREE = 6 +pkg syscall (openbsd-amd64), const MADV_FREE ideal-int +pkg syscall (openbsd-amd64), const MADV_NORMAL = 0 +pkg syscall (openbsd-amd64), const MADV_NORMAL ideal-int +pkg syscall (openbsd-amd64), const MADV_RANDOM = 1 +pkg syscall (openbsd-amd64), const MADV_RANDOM ideal-int +pkg syscall (openbsd-amd64), const MADV_SEQUENTIAL = 2 +pkg syscall (openbsd-amd64), const MADV_SEQUENTIAL ideal-int +pkg syscall (openbsd-amd64), const MADV_SPACEAVAIL = 5 +pkg syscall (openbsd-amd64), const MADV_SPACEAVAIL ideal-int +pkg syscall (openbsd-amd64), const MADV_WILLNEED = 3 +pkg syscall (openbsd-amd64), const MADV_WILLNEED ideal-int +pkg syscall (openbsd-amd64), const MAP_ANON = 4096 +pkg syscall (openbsd-amd64), const MAP_ANON ideal-int +pkg syscall (openbsd-amd64), const MAP_COPY = 4 +pkg syscall (openbsd-amd64), const MAP_COPY ideal-int +pkg syscall (openbsd-amd64), const MAP_FILE = 0 +pkg syscall (openbsd-amd64), const MAP_FILE ideal-int +pkg syscall (openbsd-amd64), const MAP_FIXED = 16 +pkg syscall (openbsd-amd64), const MAP_FIXED ideal-int +pkg syscall (openbsd-amd64), const MAP_FLAGMASK = 8183 +pkg syscall (openbsd-amd64), const MAP_FLAGMASK ideal-int +pkg syscall (openbsd-amd64), const MAP_HASSEMAPHORE = 512 +pkg syscall (openbsd-amd64), const MAP_HASSEMAPHORE ideal-int +pkg syscall (openbsd-amd64), const MAP_INHERIT = 128 +pkg syscall (openbsd-amd64), const MAP_INHERIT ideal-int +pkg syscall (openbsd-amd64), const MAP_INHERIT_COPY = 1 +pkg syscall (openbsd-amd64), const MAP_INHERIT_COPY ideal-int +pkg syscall (openbsd-amd64), const MAP_INHERIT_DONATE_COPY = 3 +pkg syscall (openbsd-amd64), const MAP_INHERIT_DONATE_COPY ideal-int +pkg syscall (openbsd-amd64), const MAP_INHERIT_NONE = 2 +pkg syscall (openbsd-amd64), const MAP_INHERIT_NONE ideal-int +pkg syscall (openbsd-amd64), const MAP_INHERIT_SHARE = 0 +pkg syscall (openbsd-amd64), const MAP_INHERIT_SHARE ideal-int +pkg syscall (openbsd-amd64), const MAP_NOEXTEND = 256 +pkg syscall (openbsd-amd64), const MAP_NOEXTEND ideal-int +pkg syscall (openbsd-amd64), const MAP_NORESERVE = 64 +pkg syscall (openbsd-amd64), const MAP_NORESERVE ideal-int +pkg syscall (openbsd-amd64), const MAP_PRIVATE = 2 +pkg syscall (openbsd-amd64), const MAP_PRIVATE ideal-int +pkg syscall (openbsd-amd64), const MAP_RENAME = 32 +pkg syscall (openbsd-amd64), const MAP_RENAME ideal-int +pkg syscall (openbsd-amd64), const MAP_SHARED = 1 +pkg syscall (openbsd-amd64), const MAP_SHARED ideal-int +pkg syscall (openbsd-amd64), const MAP_TRYFIXED = 1024 +pkg syscall (openbsd-amd64), const MAP_TRYFIXED ideal-int +pkg syscall (openbsd-amd64), const MCL_CURRENT = 1 +pkg syscall (openbsd-amd64), const MCL_CURRENT ideal-int +pkg syscall (openbsd-amd64), const MCL_FUTURE = 2 +pkg syscall (openbsd-amd64), const MCL_FUTURE ideal-int +pkg syscall (openbsd-amd64), const MS_ASYNC = 1 +pkg syscall (openbsd-amd64), const MS_ASYNC ideal-int +pkg syscall (openbsd-amd64), const MS_INVALIDATE = 4 +pkg syscall (openbsd-amd64), const MS_INVALIDATE ideal-int +pkg syscall (openbsd-amd64), const MS_SYNC = 2 +pkg syscall (openbsd-amd64), const MS_SYNC ideal-int +pkg syscall (openbsd-amd64), const PROT_EXEC = 4 +pkg syscall (openbsd-amd64), const PROT_EXEC ideal-int +pkg syscall (openbsd-amd64), const PROT_NONE = 0 +pkg syscall (openbsd-amd64), const PROT_NONE ideal-int +pkg syscall (openbsd-amd64), const PROT_READ = 1 +pkg syscall (openbsd-amd64), const PROT_READ ideal-int +pkg syscall (openbsd-amd64), const PROT_WRITE = 2 +pkg syscall (openbsd-amd64), const PROT_WRITE ideal-int +pkg syscall (openbsd-amd64), const RTF_FMASK = 1112072 +pkg syscall (openbsd-amd64), const RTM_VERSION = 5 +pkg syscall (openbsd-amd64), const SIOCBRDGDADDR = 2166909255 +pkg syscall (openbsd-amd64), const SIOCBRDGSADDR = 3240651076 +pkg syscall (openbsd-amd64), const SIOCGETVLAN = 3223349648 +pkg syscall (openbsd-amd64), const SIOCGETVLAN ideal-int +pkg syscall (openbsd-amd64), const SIOCGIFHARDMTU = 3223349669 +pkg syscall (openbsd-amd64), const SIOCGIFHARDMTU ideal-int +pkg syscall (openbsd-amd64), const SIOCGLIFPHYTTL = 3223349673 +pkg syscall (openbsd-amd64), const SIOCGLIFPHYTTL ideal-int +pkg syscall (openbsd-amd64), const SIOCGSPPPPARAMS = 3223349652 +pkg syscall (openbsd-amd64), const SIOCGSPPPPARAMS ideal-int +pkg syscall (openbsd-amd64), const SIOCGVNETID = 3223349671 +pkg syscall (openbsd-amd64), const SIOCGVNETID ideal-int +pkg syscall (openbsd-amd64), const SIOCSETVLAN = 2149607823 +pkg syscall (openbsd-amd64), const SIOCSETVLAN ideal-int +pkg syscall (openbsd-amd64), const SIOCSLIFPHYTTL = 2149607848 +pkg syscall (openbsd-amd64), const SIOCSLIFPHYTTL ideal-int +pkg syscall (openbsd-amd64), const SIOCSSPPPPARAMS = 2149607827 +pkg syscall (openbsd-amd64), const SIOCSSPPPPARAMS ideal-int +pkg syscall (openbsd-amd64), const SIOCSVNETID = 2149607846 +pkg syscall (openbsd-amd64), const SIOCSVNETID ideal-int +pkg syscall (openbsd-amd64), const SYS_CLOCK_GETRES = 89 +pkg syscall (openbsd-amd64), const SYS_CLOCK_GETTIME = 87 +pkg syscall (openbsd-amd64), const SYS_CLOCK_SETTIME = 88 +pkg syscall (openbsd-amd64), const SYS_FHSTATFS = 65 +pkg syscall (openbsd-amd64), const SYS_FSTAT = 53 +pkg syscall (openbsd-amd64), const SYS_FSTATAT = 42 +pkg syscall (openbsd-amd64), const SYS_FSTATFS = 64 +pkg syscall (openbsd-amd64), const SYS_FUTIMENS = 85 +pkg syscall (openbsd-amd64), const SYS_FUTIMES = 77 +pkg syscall (openbsd-amd64), const SYS_GETDENTS = 99 +pkg syscall (openbsd-amd64), const SYS_GETDENTS ideal-int +pkg syscall (openbsd-amd64), const SYS_GETFSSTAT = 62 +pkg syscall (openbsd-amd64), const SYS_GETITIMER = 70 +pkg syscall (openbsd-amd64), const SYS_GETRUSAGE = 19 +pkg syscall (openbsd-amd64), const SYS_GETTIMEOFDAY = 67 +pkg syscall (openbsd-amd64), const SYS_KEVENT = 72 +pkg syscall (openbsd-amd64), const SYS_LSTAT = 40 +pkg syscall (openbsd-amd64), const SYS_NANOSLEEP = 91 +pkg syscall (openbsd-amd64), const SYS_PPOLL = 109 +pkg syscall (openbsd-amd64), const SYS_PPOLL ideal-int +pkg syscall (openbsd-amd64), const SYS_PSELECT = 110 +pkg syscall (openbsd-amd64), const SYS_PSELECT ideal-int +pkg syscall (openbsd-amd64), const SYS_SELECT = 71 +pkg syscall (openbsd-amd64), const SYS_SETITIMER = 69 +pkg syscall (openbsd-amd64), const SYS_SETTIMEOFDAY = 68 +pkg syscall (openbsd-amd64), const SYS_STAT = 38 +pkg syscall (openbsd-amd64), const SYS_STATFS = 63 +pkg syscall (openbsd-amd64), const SYS_UTIMENSAT = 84 +pkg syscall (openbsd-amd64), const SYS_UTIMES = 76 +pkg syscall (openbsd-amd64), const SYS_UTRACE = 209 +pkg syscall (openbsd-amd64), const SYS_UTRACE ideal-int +pkg syscall (openbsd-amd64), const SYS_WAIT4 = 11 +pkg syscall (openbsd-amd64), const SYS___THRSLEEP = 94 +pkg syscall (openbsd-amd64), const SizeofRtMetrics = 56 +pkg syscall (openbsd-amd64), const SizeofRtMsghdr = 96 +pkg syscall (openbsd-amd64), const TCP_NOPUSH = 16 +pkg syscall (openbsd-amd64), const TCP_NOPUSH ideal-int +pkg syscall (openbsd-amd64), const TIOCGSID = 1074033763 +pkg syscall (openbsd-amd64), const TIOCGSID ideal-int +pkg syscall (openbsd-amd64), func FcntlFlock(uintptr, int, *Flock_t) error +pkg syscall (openbsd-amd64), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error) +pkg syscall (openbsd-amd64), type Dirent struct, Fileno uint64 +pkg syscall (openbsd-amd64), type Dirent struct, Off int64 +pkg syscall (openbsd-amd64), type Dirent struct, X__d_padding [4]uint8 +pkg syscall (openbsd-amd64), type FdSet struct, Bits [32]uint32 +pkg syscall (openbsd-amd64), type Kevent_t struct, Data int64 +pkg syscall (openbsd-amd64), type Kevent_t struct, Ident uint64 +pkg syscall (openbsd-amd64), type Mclpool struct, Grown int32 +pkg syscall (openbsd-amd64), type RtMetrics struct, Expire int64 +pkg syscall (openbsd-amd64), type RtMetrics struct, Pad uint32 +pkg syscall (openbsd-amd64), type Stat_t struct, Ino uint64 +pkg syscall (openbsd-amd64), type Stat_t struct, Pad_cgo_0 [4]uint8 +pkg syscall (openbsd-amd64), type Statfs_t struct, F_ctime uint64 +pkg syscall (openbsd-amd64), type Statfs_t struct, F_mntfromspec [90]int8 +pkg syscall (openbsd-amd64), type Statfs_t struct, Pad_cgo_1 [2]uint8 +pkg syscall (openbsd-amd64), type Termios struct +pkg syscall (openbsd-amd64), type Termios struct, Cc [20]uint8 +pkg syscall (openbsd-amd64), type Termios struct, Cflag uint32 +pkg syscall (openbsd-amd64), type Termios struct, Iflag uint32 +pkg syscall (openbsd-amd64), type Termios struct, Ispeed int32 +pkg syscall (openbsd-amd64), type Termios struct, Lflag uint32 +pkg syscall (openbsd-amd64), type Termios struct, Oflag uint32 +pkg syscall (openbsd-amd64), type Termios struct, Ospeed int32 +pkg syscall (openbsd-amd64), type Timespec struct, Sec int64 +pkg syscall (openbsd-amd64-cgo), const IPPROTO_DIVERT_INIT = 2 +pkg syscall (openbsd-amd64-cgo), const IPPROTO_DIVERT_INIT ideal-int +pkg syscall (openbsd-amd64-cgo), const IPPROTO_DIVERT_RESP = 1 +pkg syscall (openbsd-amd64-cgo), const IPPROTO_DIVERT_RESP ideal-int +pkg syscall (openbsd-amd64-cgo), const IPV6_RECVDSTPORT = 64 +pkg syscall (openbsd-amd64-cgo), const IPV6_RECVDSTPORT ideal-int +pkg syscall (openbsd-amd64-cgo), const IP_DIVERTFL = 4130 +pkg syscall (openbsd-amd64-cgo), const IP_DIVERTFL ideal-int +pkg syscall (openbsd-amd64-cgo), const MADV_DONTNEED = 4 +pkg syscall (openbsd-amd64-cgo), const MADV_DONTNEED ideal-int +pkg syscall (openbsd-amd64-cgo), const MADV_FREE = 6 +pkg syscall (openbsd-amd64-cgo), const MADV_FREE ideal-int +pkg syscall (openbsd-amd64-cgo), const MADV_NORMAL = 0 +pkg syscall (openbsd-amd64-cgo), const MADV_NORMAL ideal-int +pkg syscall (openbsd-amd64-cgo), const MADV_RANDOM = 1 +pkg syscall (openbsd-amd64-cgo), const MADV_RANDOM ideal-int +pkg syscall (openbsd-amd64-cgo), const MADV_SEQUENTIAL = 2 +pkg syscall (openbsd-amd64-cgo), const MADV_SEQUENTIAL ideal-int +pkg syscall (openbsd-amd64-cgo), const MADV_SPACEAVAIL = 5 +pkg syscall (openbsd-amd64-cgo), const MADV_SPACEAVAIL ideal-int +pkg syscall (openbsd-amd64-cgo), const MADV_WILLNEED = 3 +pkg syscall (openbsd-amd64-cgo), const MADV_WILLNEED ideal-int +pkg syscall (openbsd-amd64-cgo), const MAP_ANON = 4096 +pkg syscall (openbsd-amd64-cgo), const MAP_ANON ideal-int +pkg syscall (openbsd-amd64-cgo), const MAP_COPY = 4 +pkg syscall (openbsd-amd64-cgo), const MAP_COPY ideal-int +pkg syscall (openbsd-amd64-cgo), const MAP_FILE = 0 +pkg syscall (openbsd-amd64-cgo), const MAP_FILE ideal-int +pkg syscall (openbsd-amd64-cgo), const MAP_FIXED = 16 +pkg syscall (openbsd-amd64-cgo), const MAP_FIXED ideal-int +pkg syscall (openbsd-amd64-cgo), const MAP_FLAGMASK = 8183 +pkg syscall (openbsd-amd64-cgo), const MAP_FLAGMASK ideal-int +pkg syscall (openbsd-amd64-cgo), const MAP_HASSEMAPHORE = 512 +pkg syscall (openbsd-amd64-cgo), const MAP_HASSEMAPHORE ideal-int +pkg syscall (openbsd-amd64-cgo), const MAP_INHERIT = 128 +pkg syscall (openbsd-amd64-cgo), const MAP_INHERIT ideal-int +pkg syscall (openbsd-amd64-cgo), const MAP_INHERIT_COPY = 1 +pkg syscall (openbsd-amd64-cgo), const MAP_INHERIT_COPY ideal-int +pkg syscall (openbsd-amd64-cgo), const MAP_INHERIT_DONATE_COPY = 3 +pkg syscall (openbsd-amd64-cgo), const MAP_INHERIT_DONATE_COPY ideal-int +pkg syscall (openbsd-amd64-cgo), const MAP_INHERIT_NONE = 2 +pkg syscall (openbsd-amd64-cgo), const MAP_INHERIT_NONE ideal-int +pkg syscall (openbsd-amd64-cgo), const MAP_INHERIT_SHARE = 0 +pkg syscall (openbsd-amd64-cgo), const MAP_INHERIT_SHARE ideal-int +pkg syscall (openbsd-amd64-cgo), const MAP_NOEXTEND = 256 +pkg syscall (openbsd-amd64-cgo), const MAP_NOEXTEND ideal-int +pkg syscall (openbsd-amd64-cgo), const MAP_NORESERVE = 64 +pkg syscall (openbsd-amd64-cgo), const MAP_NORESERVE ideal-int +pkg syscall (openbsd-amd64-cgo), const MAP_PRIVATE = 2 +pkg syscall (openbsd-amd64-cgo), const MAP_PRIVATE ideal-int +pkg syscall (openbsd-amd64-cgo), const MAP_RENAME = 32 +pkg syscall (openbsd-amd64-cgo), const MAP_RENAME ideal-int +pkg syscall (openbsd-amd64-cgo), const MAP_SHARED = 1 +pkg syscall (openbsd-amd64-cgo), const MAP_SHARED ideal-int +pkg syscall (openbsd-amd64-cgo), const MAP_TRYFIXED = 1024 +pkg syscall (openbsd-amd64-cgo), const MAP_TRYFIXED ideal-int +pkg syscall (openbsd-amd64-cgo), const MCL_CURRENT = 1 +pkg syscall (openbsd-amd64-cgo), const MCL_CURRENT ideal-int +pkg syscall (openbsd-amd64-cgo), const MCL_FUTURE = 2 +pkg syscall (openbsd-amd64-cgo), const MCL_FUTURE ideal-int +pkg syscall (openbsd-amd64-cgo), const MS_ASYNC = 1 +pkg syscall (openbsd-amd64-cgo), const MS_ASYNC ideal-int +pkg syscall (openbsd-amd64-cgo), const MS_INVALIDATE = 4 +pkg syscall (openbsd-amd64-cgo), const MS_INVALIDATE ideal-int +pkg syscall (openbsd-amd64-cgo), const MS_SYNC = 2 +pkg syscall (openbsd-amd64-cgo), const MS_SYNC ideal-int +pkg syscall (openbsd-amd64-cgo), const PROT_EXEC = 4 +pkg syscall (openbsd-amd64-cgo), const PROT_EXEC ideal-int +pkg syscall (openbsd-amd64-cgo), const PROT_NONE = 0 +pkg syscall (openbsd-amd64-cgo), const PROT_NONE ideal-int +pkg syscall (openbsd-amd64-cgo), const PROT_READ = 1 +pkg syscall (openbsd-amd64-cgo), const PROT_READ ideal-int +pkg syscall (openbsd-amd64-cgo), const PROT_WRITE = 2 +pkg syscall (openbsd-amd64-cgo), const PROT_WRITE ideal-int +pkg syscall (openbsd-amd64-cgo), const RTF_FMASK = 1112072 +pkg syscall (openbsd-amd64-cgo), const RTM_VERSION = 5 +pkg syscall (openbsd-amd64-cgo), const SIOCBRDGDADDR = 2166909255 +pkg syscall (openbsd-amd64-cgo), const SIOCBRDGSADDR = 3240651076 +pkg syscall (openbsd-amd64-cgo), const SIOCGETVLAN = 3223349648 +pkg syscall (openbsd-amd64-cgo), const SIOCGETVLAN ideal-int +pkg syscall (openbsd-amd64-cgo), const SIOCGIFHARDMTU = 3223349669 +pkg syscall (openbsd-amd64-cgo), const SIOCGIFHARDMTU ideal-int +pkg syscall (openbsd-amd64-cgo), const SIOCGLIFPHYTTL = 3223349673 +pkg syscall (openbsd-amd64-cgo), const SIOCGLIFPHYTTL ideal-int +pkg syscall (openbsd-amd64-cgo), const SIOCGSPPPPARAMS = 3223349652 +pkg syscall (openbsd-amd64-cgo), const SIOCGSPPPPARAMS ideal-int +pkg syscall (openbsd-amd64-cgo), const SIOCGVNETID = 3223349671 +pkg syscall (openbsd-amd64-cgo), const SIOCGVNETID ideal-int +pkg syscall (openbsd-amd64-cgo), const SIOCSETVLAN = 2149607823 +pkg syscall (openbsd-amd64-cgo), const SIOCSETVLAN ideal-int +pkg syscall (openbsd-amd64-cgo), const SIOCSLIFPHYTTL = 2149607848 +pkg syscall (openbsd-amd64-cgo), const SIOCSLIFPHYTTL ideal-int +pkg syscall (openbsd-amd64-cgo), const SIOCSSPPPPARAMS = 2149607827 +pkg syscall (openbsd-amd64-cgo), const SIOCSSPPPPARAMS ideal-int +pkg syscall (openbsd-amd64-cgo), const SIOCSVNETID = 2149607846 +pkg syscall (openbsd-amd64-cgo), const SIOCSVNETID ideal-int +pkg syscall (openbsd-amd64-cgo), const SYS_CLOCK_GETRES = 89 +pkg syscall (openbsd-amd64-cgo), const SYS_CLOCK_GETTIME = 87 +pkg syscall (openbsd-amd64-cgo), const SYS_CLOCK_SETTIME = 88 +pkg syscall (openbsd-amd64-cgo), const SYS_FHSTATFS = 65 +pkg syscall (openbsd-amd64-cgo), const SYS_FSTAT = 53 +pkg syscall (openbsd-amd64-cgo), const SYS_FSTATAT = 42 +pkg syscall (openbsd-amd64-cgo), const SYS_FSTATFS = 64 +pkg syscall (openbsd-amd64-cgo), const SYS_FUTIMENS = 85 +pkg syscall (openbsd-amd64-cgo), const SYS_FUTIMES = 77 +pkg syscall (openbsd-amd64-cgo), const SYS_GETDENTS = 99 +pkg syscall (openbsd-amd64-cgo), const SYS_GETDENTS ideal-int +pkg syscall (openbsd-amd64-cgo), const SYS_GETFSSTAT = 62 +pkg syscall (openbsd-amd64-cgo), const SYS_GETITIMER = 70 +pkg syscall (openbsd-amd64-cgo), const SYS_GETRUSAGE = 19 +pkg syscall (openbsd-amd64-cgo), const SYS_GETTIMEOFDAY = 67 +pkg syscall (openbsd-amd64-cgo), const SYS_KEVENT = 72 +pkg syscall (openbsd-amd64-cgo), const SYS_LSTAT = 40 +pkg syscall (openbsd-amd64-cgo), const SYS_NANOSLEEP = 91 +pkg syscall (openbsd-amd64-cgo), const SYS_PPOLL = 109 +pkg syscall (openbsd-amd64-cgo), const SYS_PPOLL ideal-int +pkg syscall (openbsd-amd64-cgo), const SYS_PSELECT = 110 +pkg syscall (openbsd-amd64-cgo), const SYS_PSELECT ideal-int +pkg syscall (openbsd-amd64-cgo), const SYS_SELECT = 71 +pkg syscall (openbsd-amd64-cgo), const SYS_SETITIMER = 69 +pkg syscall (openbsd-amd64-cgo), const SYS_SETTIMEOFDAY = 68 +pkg syscall (openbsd-amd64-cgo), const SYS_STAT = 38 +pkg syscall (openbsd-amd64-cgo), const SYS_STATFS = 63 +pkg syscall (openbsd-amd64-cgo), const SYS_UTIMENSAT = 84 +pkg syscall (openbsd-amd64-cgo), const SYS_UTIMES = 76 +pkg syscall (openbsd-amd64-cgo), const SYS_UTRACE = 209 +pkg syscall (openbsd-amd64-cgo), const SYS_UTRACE ideal-int +pkg syscall (openbsd-amd64-cgo), const SYS_WAIT4 = 11 +pkg syscall (openbsd-amd64-cgo), const SYS___THRSLEEP = 94 +pkg syscall (openbsd-amd64-cgo), const SizeofRtMetrics = 56 +pkg syscall (openbsd-amd64-cgo), const SizeofRtMsghdr = 96 +pkg syscall (openbsd-amd64-cgo), const TCP_NOPUSH = 16 +pkg syscall (openbsd-amd64-cgo), const TCP_NOPUSH ideal-int +pkg syscall (openbsd-amd64-cgo), const TIOCGSID = 1074033763 +pkg syscall (openbsd-amd64-cgo), const TIOCGSID ideal-int +pkg syscall (openbsd-amd64-cgo), func FcntlFlock(uintptr, int, *Flock_t) error +pkg syscall (openbsd-amd64-cgo), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error) +pkg syscall (openbsd-amd64-cgo), type Dirent struct, Fileno uint64 +pkg syscall (openbsd-amd64-cgo), type Dirent struct, Off int64 +pkg syscall (openbsd-amd64-cgo), type Dirent struct, X__d_padding [4]uint8 +pkg syscall (openbsd-amd64-cgo), type FdSet struct, Bits [32]uint32 +pkg syscall (openbsd-amd64-cgo), type Kevent_t struct, Data int64 +pkg syscall (openbsd-amd64-cgo), type Kevent_t struct, Ident uint64 +pkg syscall (openbsd-amd64-cgo), type Mclpool struct, Grown int32 +pkg syscall (openbsd-amd64-cgo), type RtMetrics struct, Expire int64 +pkg syscall (openbsd-amd64-cgo), type RtMetrics struct, Pad uint32 +pkg syscall (openbsd-amd64-cgo), type Stat_t struct, Ino uint64 +pkg syscall (openbsd-amd64-cgo), type Stat_t struct, Pad_cgo_0 [4]uint8 +pkg syscall (openbsd-amd64-cgo), type Statfs_t struct, F_ctime uint64 +pkg syscall (openbsd-amd64-cgo), type Statfs_t struct, F_mntfromspec [90]int8 +pkg syscall (openbsd-amd64-cgo), type Statfs_t struct, Pad_cgo_1 [2]uint8 +pkg syscall (openbsd-amd64-cgo), type Termios struct +pkg syscall (openbsd-amd64-cgo), type Termios struct, Cc [20]uint8 +pkg syscall (openbsd-amd64-cgo), type Termios struct, Cflag uint32 +pkg syscall (openbsd-amd64-cgo), type Termios struct, Iflag uint32 +pkg syscall (openbsd-amd64-cgo), type Termios struct, Ispeed int32 +pkg syscall (openbsd-amd64-cgo), type Termios struct, Lflag uint32 +pkg syscall (openbsd-amd64-cgo), type Termios struct, Oflag uint32 +pkg syscall (openbsd-amd64-cgo), type Termios struct, Ospeed int32 +pkg syscall (openbsd-amd64-cgo), type Timespec struct, Sec int64 +pkg syscall (windows-386), const ERROR_MORE_DATA = 234 +pkg syscall (windows-386), const ERROR_MORE_DATA Errno +pkg syscall (windows-386), const ERROR_NETNAME_DELETED = 64 +pkg syscall (windows-386), const ERROR_NETNAME_DELETED Errno +pkg syscall (windows-386), const IOC_VENDOR = 402653184 +pkg syscall (windows-386), const IOC_VENDOR ideal-int +pkg syscall (windows-386), const SIO_KEEPALIVE_VALS = 2550136836 +pkg syscall (windows-386), const SIO_KEEPALIVE_VALS ideal-int +pkg syscall (windows-386), const WSAECONNRESET = 10054 +pkg syscall (windows-386), const WSAECONNRESET Errno +pkg syscall (windows-386), func NewCallbackCDecl(interface{}) uintptr +pkg syscall (windows-386), type TCPKeepalive struct +pkg syscall (windows-386), type TCPKeepalive struct, Interval uint32 +pkg syscall (windows-386), type TCPKeepalive struct, OnOff uint32 +pkg syscall (windows-386), type TCPKeepalive struct, Time uint32 +pkg syscall (windows-amd64), const ERROR_MORE_DATA = 234 +pkg syscall (windows-amd64), const ERROR_MORE_DATA Errno +pkg syscall (windows-amd64), const ERROR_NETNAME_DELETED = 64 +pkg syscall (windows-amd64), const ERROR_NETNAME_DELETED Errno +pkg syscall (windows-amd64), const IOC_VENDOR = 402653184 +pkg syscall (windows-amd64), const IOC_VENDOR ideal-int +pkg syscall (windows-amd64), const SIO_KEEPALIVE_VALS = 2550136836 +pkg syscall (windows-amd64), const SIO_KEEPALIVE_VALS ideal-int +pkg syscall (windows-amd64), const WSAECONNRESET = 10054 +pkg syscall (windows-amd64), const WSAECONNRESET Errno +pkg syscall (windows-amd64), func NewCallbackCDecl(interface{}) uintptr +pkg syscall (windows-amd64), type TCPKeepalive struct +pkg syscall (windows-amd64), type TCPKeepalive struct, Interval uint32 +pkg syscall (windows-amd64), type TCPKeepalive struct, OnOff uint32 +pkg syscall (windows-amd64), type TCPKeepalive struct, Time uint32 +pkg testing, method (*B) RunParallel(func(*PB)) +pkg testing, method (*B) SetParallelism(int) +pkg testing, method (*PB) Next() bool +pkg testing, type PB struct +pkg unicode, const Version = "6.3.0" diff --git a/api/next.txt b/api/next.txt index e69de29bb..5e49b3f94 100644 --- a/api/next.txt +++ b/api/next.txt @@ -0,0 +1,117 @@ +pkg debug/goobj, const SBSS = 21 +pkg debug/goobj, const SBSS SymKind +pkg debug/goobj, const SCONST = 31 +pkg debug/goobj, const SCONST SymKind +pkg debug/goobj, const SDATA = 19 +pkg debug/goobj, const SDATA SymKind +pkg debug/goobj, const SDYNIMPORT = 32 +pkg debug/goobj, const SDYNIMPORT SymKind +pkg debug/goobj, const SELFROSECT = 12 +pkg debug/goobj, const SELFROSECT SymKind +pkg debug/goobj, const SELFRXSECT = 2 +pkg debug/goobj, const SELFRXSECT SymKind +pkg debug/goobj, const SELFSECT = 14 +pkg debug/goobj, const SELFSECT SymKind +pkg debug/goobj, const SFILE = 29 +pkg debug/goobj, const SFILE SymKind +pkg debug/goobj, const SFILEPATH = 30 +pkg debug/goobj, const SFILEPATH SymKind +pkg debug/goobj, const SFUNCTAB = 8 +pkg debug/goobj, const SFUNCTAB SymKind +pkg debug/goobj, const SGOFUNC = 6 +pkg debug/goobj, const SGOFUNC SymKind +pkg debug/goobj, const SGOSTRING = 5 +pkg debug/goobj, const SGOSTRING SymKind +pkg debug/goobj, const SHOSTOBJ = 33 +pkg debug/goobj, const SHOSTOBJ SymKind +pkg debug/goobj, const SINITARR = 18 +pkg debug/goobj, const SINITARR SymKind +pkg debug/goobj, const SMACHO = 15 +pkg debug/goobj, const SMACHO SymKind +pkg debug/goobj, const SMACHOGOT = 16 +pkg debug/goobj, const SMACHOGOT SymKind +pkg debug/goobj, const SMACHOINDIRECTGOT = 28 +pkg debug/goobj, const SMACHOINDIRECTGOT SymKind +pkg debug/goobj, const SMACHOINDIRECTPLT = 27 +pkg debug/goobj, const SMACHOINDIRECTPLT SymKind +pkg debug/goobj, const SMACHOPLT = 13 +pkg debug/goobj, const SMACHOPLT SymKind +pkg debug/goobj, const SMACHOSYMSTR = 25 +pkg debug/goobj, const SMACHOSYMSTR SymKind +pkg debug/goobj, const SMACHOSYMTAB = 26 +pkg debug/goobj, const SMACHOSYMTAB SymKind +pkg debug/goobj, const SNOPTRBSS = 22 +pkg debug/goobj, const SNOPTRBSS SymKind +pkg debug/goobj, const SNOPTRDATA = 17 +pkg debug/goobj, const SNOPTRDATA SymKind +pkg debug/goobj, const SPCLNTAB = 11 +pkg debug/goobj, const SPCLNTAB SymKind +pkg debug/goobj, const SRODATA = 7 +pkg debug/goobj, const SRODATA SymKind +pkg debug/goobj, const SSTRING = 4 +pkg debug/goobj, const SSTRING SymKind +pkg debug/goobj, const SSYMTAB = 10 +pkg debug/goobj, const SSYMTAB SymKind +pkg debug/goobj, const STEXT = 1 +pkg debug/goobj, const STEXT SymKind +pkg debug/goobj, const STLSBSS = 23 +pkg debug/goobj, const STLSBSS SymKind +pkg debug/goobj, const STYPE = 3 +pkg debug/goobj, const STYPE SymKind +pkg debug/goobj, const STYPELINK = 9 +pkg debug/goobj, const STYPELINK SymKind +pkg debug/goobj, const SWINDOWS = 20 +pkg debug/goobj, const SWINDOWS SymKind +pkg debug/goobj, const SXREF = 24 +pkg debug/goobj, const SXREF SymKind +pkg debug/goobj, func Parse(io.ReadSeeker, string) (*Package, error) +pkg debug/goobj, method (Sym) String() string +pkg debug/goobj, method (SymID) String() string +pkg debug/goobj, method (SymKind) String() string +pkg debug/goobj, type Data struct +pkg debug/goobj, type Data struct, Offset int64 +pkg debug/goobj, type Data struct, Size int64 +pkg debug/goobj, type Func struct +pkg debug/goobj, type Func struct, Args int +pkg debug/goobj, type Func struct, File []string +pkg debug/goobj, type Func struct, Frame int +pkg debug/goobj, type Func struct, FuncData []FuncData +pkg debug/goobj, type Func struct, Leaf bool +pkg debug/goobj, type Func struct, NoSplit bool +pkg debug/goobj, type Func struct, PCData []Data +pkg debug/goobj, type Func struct, PCFile Data +pkg debug/goobj, type Func struct, PCLine Data +pkg debug/goobj, type Func struct, PCSP Data +pkg debug/goobj, type Func struct, Var []Var +pkg debug/goobj, type FuncData struct +pkg debug/goobj, type FuncData struct, Offset int64 +pkg debug/goobj, type FuncData struct, Sym SymID +pkg debug/goobj, type Package struct +pkg debug/goobj, type Package struct, ImportPath string +pkg debug/goobj, type Package struct, Imports []string +pkg debug/goobj, type Package struct, MaxVersion int +pkg debug/goobj, type Package struct, Syms []*Sym +pkg debug/goobj, type Reloc struct +pkg debug/goobj, type Reloc struct, Add int +pkg debug/goobj, type Reloc struct, Offset int +pkg debug/goobj, type Reloc struct, Size int +pkg debug/goobj, type Reloc struct, Sym SymID +pkg debug/goobj, type Reloc struct, Type int +pkg debug/goobj, type Sym struct +pkg debug/goobj, type Sym struct, Data Data +pkg debug/goobj, type Sym struct, DupOK bool +pkg debug/goobj, type Sym struct, Func *Func +pkg debug/goobj, type Sym struct, Kind SymKind +pkg debug/goobj, type Sym struct, Reloc []Reloc +pkg debug/goobj, type Sym struct, Size int +pkg debug/goobj, type Sym struct, Type SymID +pkg debug/goobj, type Sym struct, embedded SymID +pkg debug/goobj, type SymID struct +pkg debug/goobj, type SymID struct, Name string +pkg debug/goobj, type SymID struct, Version int +pkg debug/goobj, type SymKind int +pkg debug/goobj, type Var struct +pkg debug/goobj, type Var struct, Kind int +pkg debug/goobj, type Var struct, Name string +pkg debug/goobj, type Var struct, Offset int +pkg debug/goobj, type Var struct, Type SymID diff --git a/doc/Makefile b/doc/Makefile deleted file mode 100644 index 23262da94..000000000 --- a/doc/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2009 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. - -RAWHTML=\ - articles/defer_panic_recover.rawhtml\ - articles/error_handling.rawhtml\ - articles/slices_usage_and_internals.rawhtml\ - articles/laws_of_reflection.rawhtml\ - articles/c_go_cgo.rawhtml\ - articles/concurrency_patterns.rawhtml\ - articles/godoc_documenting_go_code.rawhtml\ - articles/gobs_of_data.rawhtml\ - articles/json_and_go.rawhtml\ - articles/json_rpc_tale_of_interfaces.rawhtml\ - articles/image_draw.rawhtml\ - articles/image_package.rawhtml\ - effective_go.rawhtml\ - go1.rawhtml\ - -all: $(RAWHTML) - -%.rawhtml: %.html - godoc -url /doc/$< >$@ - -clean: - rm -f $(RAWHTML) - -compare: - for i in $(RAWHTML); do \ - godoc -url /doc/$${i/.rawhtml/.html} | diff -u $$i -; \ - done diff --git a/doc/articles/race_detector.html b/doc/articles/race_detector.html new file mode 100644 index 000000000..282db8ba4 --- /dev/null +++ b/doc/articles/race_detector.html @@ -0,0 +1,388 @@ + + +

Introduction

+ +

+Data races are among the most common and hardest to debug types of bugs in concurrent systems. +A data race occurs when two goroutines access the same variable concurrently and at least one of the accesses is a write. +See the The Go Memory Model for details. +

+ +

+Here is an example of a data race that can lead to crashes and memory corruption: +

+ +
+func main() {
+	c := make(chan bool)
+	m := make(map[string]string)
+	go func() {
+		m["1"] = "a" // First conflicting access.
+		c <- true
+	}()
+	m["2"] = "b" // Second conflicting access.
+	<-c
+	for k, v := range m {
+		fmt.Println(k, v)
+	}
+}
+
+ +

Usage

+ +

+To help diagnose such bugs, Go includes a built-in data race detector. +To use it, add the -race flag to the go command: +

+ +
+$ go test -race mypkg    // to test the package
+$ go run -race mysrc.go  // to run the source file
+$ go build -race mycmd   // to build the command
+$ go install -race mypkg // to install the package
+
+ +

Report Format

+ +

+When the race detector finds a data race in the program, it prints a report. +The report contains stack traces for conflicting accesses, as well as stacks where the involved goroutines were created. +Here is an example: +

+ +
+WARNING: DATA RACE
+Read by goroutine 185:
+  net.(*pollServer).AddFD()
+      src/pkg/net/fd_unix.go:89 +0x398
+  net.(*pollServer).WaitWrite()
+      src/pkg/net/fd_unix.go:247 +0x45
+  net.(*netFD).Write()
+      src/pkg/net/fd_unix.go:540 +0x4d4
+  net.(*conn).Write()
+      src/pkg/net/net.go:129 +0x101
+  net.func·060()
+      src/pkg/net/timeout_test.go:603 +0xaf
+
+Previous write by goroutine 184:
+  net.setWriteDeadline()
+      src/pkg/net/sockopt_posix.go:135 +0xdf
+  net.setDeadline()
+      src/pkg/net/sockopt_posix.go:144 +0x9c
+  net.(*conn).SetDeadline()
+      src/pkg/net/net.go:161 +0xe3
+  net.func·061()
+      src/pkg/net/timeout_test.go:616 +0x3ed
+
+Goroutine 185 (running) created at:
+  net.func·061()
+      src/pkg/net/timeout_test.go:609 +0x288
+
+Goroutine 184 (running) created at:
+  net.TestProlongTimeout()
+      src/pkg/net/timeout_test.go:618 +0x298
+  testing.tRunner()
+      src/pkg/testing/testing.go:301 +0xe8
+
+ +

Options

+ +

+The GORACE environment variable sets race detector options. +The format is: +

+ +
+GORACE="option1=val1 option2=val2"
+
+ +

+The options are: +

+ +
    +
  • +log_path (default stderr): The race detector writes +its report to a file named log_path.pid. +The special names stdout +and stderr cause reports to be written to standard output and +standard error, respectively. +
  • + +
  • +exitcode (default 66): The exit status to use when +exiting after a detected race. +
  • + +
  • +strip_path_prefix (default ""): Strip this prefix +from all reported file paths, to make reports more concise. +
  • + +
  • +history_size (default 1): The per-goroutine memory +access history is 32K * 2**history_size elements. +Increasing this value can avoid a "failed to restore the stack" error in reports, at the +cost of increased memory usage. +
  • + +
  • +halt_on_error (default 0): Controls whether the program +exits after reporting first data race. +
  • +
+ +

+Example: +

+ +
+$ GORACE="log_path=/tmp/race/report strip_path_prefix=/my/go/sources/" go test -race
+
+ +

Excluding Tests

+ +

+When you build with -race flag, the go command defines additional +build tag race. +You can use the tag to exclude some code and tests when running the race detector. +Some examples: +

+ +
+// +build !race
+
+package foo
+
+// The test contains a data race. See issue 123.
+func TestFoo(t *testing.T) {
+	// ...
+}
+
+// The test fails under the race detector due to timeouts.
+func TestBar(t *testing.T) {
+	// ...
+}
+
+// The test takes too long under the race detector.
+func TestBaz(t *testing.T) {
+	// ...
+}
+
+ +

How To Use

+ +

+To start, run your tests using the race detector (go test -race). +The race detector only finds races that happen at runtime, so it can't find +races in code paths that are not executed. +If your tests have incomplete coverage, +you may find more races by running a binary built with -race under a realistic +workload. +

+ +

Typical Data Races

+ +

+Here are some typical data races. All of them can be detected with the race detector. +

+ +

Race on loop counter

+ +
+func main() {
+	var wg sync.WaitGroup
+	wg.Add(5)
+	for i := 0; i < 5; i++ {
+		go func() {
+			fmt.Println(i) // Not the 'i' you are looking for.
+			wg.Done()
+		}()
+	}
+	wg.Wait()
+}
+
+ +

+The variable i in the function literal is the same variable used by the loop, so +the read in the goroutine races with the loop increment. +(This program typically prints 55555, not 01234.) +The program can be fixed by making a copy of the variable: +

+ +
+func main() {
+	var wg sync.WaitGroup
+	wg.Add(5)
+	for i := 0; i < 5; i++ {
+		go func(j int) {
+			fmt.Println(j) // Good. Read local copy of the loop counter.
+			wg.Done()
+		}(i)
+	}
+	wg.Wait()
+}
+
+ +

Accidentally shared variable

+ +
+// ParallelWrite writes data to file1 and file2, returns the errors.
+func ParallelWrite(data []byte) chan error {
+	res := make(chan error, 2)
+	f1, err := os.Create("file1")
+	if err != nil {
+		res <- err
+	} else {
+		go func() {
+			// This err is shared with the main goroutine,
+			// so the write races with the write below.
+			_, err = f1.Write(data)
+			res <- err
+			f1.Close()
+		}()
+	}
+	f2, err := os.Create("file2") // The second conflicting write to err.
+	if err != nil {
+		res <- err
+	} else {
+		go func() {
+			_, err = f2.Write(data)
+			res <- err
+			f2.Close()
+		}()
+	}
+	return res
+}
+
+ +

+The fix is to introduce new variables in the goroutines (note the use of :=): +

+ +
+			...
+			_, err := f1.Write(data)
+			...
+			_, err := f2.Write(data)
+			...
+
+ +

Unprotected global variable

+ +

+If the following code is called from several goroutines, it leads to races on the service map. +Concurrent reads and writes of the same map are not safe: +

+ +
+var service map[string]net.Addr
+
+func RegisterService(name string, addr net.Addr) {
+	service[name] = addr
+}
+
+func LookupService(name string) net.Addr {
+	return service[name]
+}
+
+ +

+To make the code safe, protect the accesses with a mutex: +

+ +
+var (
+	service   map[string]net.Addr
+	serviceMu sync.Mutex
+)
+
+func RegisterService(name string, addr net.Addr) {
+	serviceMu.Lock()
+	defer serviceMu.Unlock()
+	service[name] = addr
+}
+
+func LookupService(name string) net.Addr {
+	serviceMu.Lock()
+	defer serviceMu.Unlock()
+	return service[name]
+}
+
+ +

Primitive unprotected variable

+ +

+Data races can happen on variables of primitive types as well (bool, int, int64, etc.), +as in this example: +

+ +
+type Watchdog struct{ last int64 }
+
+func (w *Watchdog) KeepAlive() {
+	w.last = time.Now().UnixNano() // First conflicting access.
+}
+
+func (w *Watchdog) Start() {
+	go func() {
+		for {
+			time.Sleep(time.Second)
+			// Second conflicting access.
+			if w.last < time.Now().Add(-10*time.Second).UnixNano() {
+				fmt.Println("No keepalives for 10 seconds. Dying.")
+				os.Exit(1)
+			}
+		}
+	}()
+}
+
+ +

+Even such "innocent" data races can lead to hard-to-debug problems caused by +non-atomicity of the memory accesses, +interference with compiler optimizations, +or reordering issues accessing processor memory . +

+ +

+A typical fix for this race is to use a channel or a mutex. +To preserve the lock-free behavior, one can also use the +sync/atomic package. +

+ +
+type Watchdog struct{ last int64 }
+
+func (w *Watchdog) KeepAlive() {
+	atomic.StoreInt64(&w.last, time.Now().UnixNano())
+}
+
+func (w *Watchdog) Start() {
+	go func() {
+		for {
+			time.Sleep(time.Second)
+			if atomic.LoadInt64(&w.last) < time.Now().Add(-10*time.Second).UnixNano() {
+				fmt.Println("No keepalives for 10 seconds. Dying.")
+				os.Exit(1)
+			}
+		}
+	}()
+}
+
+ +

Supported Systems

+ +

+The race detector runs on darwin/amd64, linux/amd64, and windows/amd64. +

+ +

Runtime Overhead

+ +

+The cost of race detection varies by program, but for a typical program, memory +usage may increase by 5-10x and execution time by 2-20x. +

diff --git a/doc/articles/wiki/Makefile b/doc/articles/wiki/Makefile deleted file mode 100644 index e40b1311e..000000000 --- a/doc/articles/wiki/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# 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. - -all: index.html - -CLEANFILES:=get.bin final-test.bin a.out - -clean: - rm -f $(CLEANFILES) diff --git a/doc/articles/wiki/final.go b/doc/articles/wiki/final.go index f15794d66..d84c1ffb2 100644 --- a/doc/articles/wiki/final.go +++ b/doc/articles/wiki/final.go @@ -5,12 +5,19 @@ package main import ( + "flag" "html/template" "io/ioutil" + "log" + "net" "net/http" "regexp" ) +var ( + addr = flag.Bool("addr", false, "find open address and print to final-port.txt") +) + type Page struct { Title string Body []byte @@ -81,8 +88,24 @@ func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.Handl } func main() { + flag.Parse() http.HandleFunc("/view/", makeHandler(viewHandler)) http.HandleFunc("/edit/", makeHandler(editHandler)) http.HandleFunc("/save/", makeHandler(saveHandler)) + + if *addr { + l, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + log.Fatal(err) + } + err = ioutil.WriteFile("final-port.txt", []byte(l.Addr().String()), 0644) + if err != nil { + log.Fatal(err) + } + s := &http.Server{} + s.Serve(l) + return + } + http.ListenAndServe(":8080", nil) } diff --git a/doc/articles/wiki/index.html b/doc/articles/wiki/index.html index 7bf7213e8..b6b080df9 100644 --- a/doc/articles/wiki/index.html +++ b/doc/articles/wiki/index.html @@ -466,7 +466,7 @@ header to the HTTP response.

The function saveHandler will handle the submission of forms located on the edit pages. After uncommenting the related line in -main, let's implement the the handler: +main, let's implement the handler:

{{code "doc/articles/wiki/final-template.go" `/^func saveHandler/` `/^}/`}} diff --git a/doc/articles/wiki/test.bash b/doc/articles/wiki/test.bash index 54a632c30..2997f1680 100755 --- a/doc/articles/wiki/test.bash +++ b/doc/articles/wiki/test.bash @@ -7,10 +7,12 @@ set -e wiki_pid= cleanup() { kill $wiki_pid - rm -f test_*.out Test.txt final-test.bin final-test.go a.out get.bin + rm -f test_*.out Test.txt final.bin final-port.txt a.out get.bin } trap cleanup 0 INT +rm -f get.bin final.bin a.out + # If called with -all, check that all code snippets compile. if [ "$1" == "-all" ]; then for fn in *.go; do @@ -19,13 +21,25 @@ if [ "$1" == "-all" ]; then fi go build -o get.bin get.go -addr=$(./get.bin -addr) -sed s/:8080/$addr/ < final.go > final-test.go -go build -o final-test.bin final-test.go -(./final-test.bin) & +go build -o final.bin final.go +(./final.bin --addr) & wiki_pid=$! -./get.bin --wait_for_port=5s http://$addr/edit/Test > test_edit.out +l=0 +while [ ! -f ./final-port.txt ] +do + l=$(($l+1)) + if [ "$l" -gt 5 ] + then + echo "port not available within 5 seconds" + exit 1 + break + fi + sleep 1 +done + +addr=$(cat final-port.txt) +./get.bin http://$addr/edit/Test > test_edit.out diff -u test_edit.out test_edit.good ./get.bin -post=body=some%20content http://$addr/save/Test > test_save.out diff -u test_save.out test_view.good # should be the same as viewing diff --git a/doc/asm.html b/doc/asm.html index b855b9ef7..d44cb799d 100644 --- a/doc/asm.html +++ b/doc/asm.html @@ -8,7 +8,11 @@

This document is a quick outline of the unusual form of assembly language used by the gc suite of Go compilers (6g, 8g, etc.). -It is based on the input to the Plan 9 assemblers, which is documented in detail +The document is not comprehensive. +

+ +

+The assembler is based on the input to the Plan 9 assemblers, which is documented in detail on the Plan 9 site. If you plan to write assembly language, you should read that document although much of it is Plan 9-specific. This document provides a summary of the syntax and @@ -70,6 +74,8 @@ The FUNCDATA and PCDATA directives contain information for use by the garbage collector; they are introduced by the compiler.

+

Symbols

@@ -194,7 +201,7 @@ TEXT runtime·profileloop(SB),NOSPLIT,$8

In the general case, the frame size is followed by an argument size, separated by a minus sign. -(It's not an subtraction, just idiosyncratic syntax.) +(It's not a subtraction, just idiosyncratic syntax.) The frame size $24-8 states that the function has a 24-byte frame and is called with 8 bytes of argument, which live on the caller's frame. If NOSPLIT is not specified for the TEXT, diff --git a/doc/codewalk/sharemem.xml b/doc/codewalk/sharemem.xml index d443e176e..8b47f12b7 100644 --- a/doc/codewalk/sharemem.xml +++ b/doc/codewalk/sharemem.xml @@ -171,7 +171,7 @@ and/or writes to a shared map. In this codewalk we have explored a simple example of using Go's concurrency -primitives to share memory through commmunication. +primitives to share memory through communication.

This should provide a starting point from which to explore the ways in which goroutines and channels can be used to write expressive and concise concurrent diff --git a/doc/contrib.html b/doc/contrib.html index 048a5d97f..6529c91d5 100644 --- a/doc/contrib.html +++ b/doc/contrib.html @@ -37,16 +37,13 @@ We encourage all Go users to subscribe to A guide for updating your code to work with Go 1.

-

Go 1.1 Release Notes

+

Go 1.1 Release Notes

-A list of significant changes in Go 1.1, with instructions for updating your -code where necessary. -

- -

Go 1.2 Release Notes

-

-A list of significant changes in Go 1.2, with instructions for updating your -code where necessary. +A list of significant changes in Go 1.1, with instructions for updating +your code where necessary. +Each point release includes a similar document appropriate for that +release: Go 1.2, Go 1.3, +and so on.

Go 1 and the Future of Go Programs

@@ -61,15 +58,22 @@ Go 1 matures.

Source Code

Check out the Go source code.

-

Developer Mailing List

-

The golang-dev -mailing list is for discussing and reviewing code for the Go project.

+

Developer and +Code Review Mailing List

+

The golang-dev +mailing list is for discussing code changes to the Go project. +The golang-codereviews +mailing list is for actual reviewing of the code changes (CLs).

+

For general discussion of Go programming, see golang-nuts.

+href="https://groups.google.com/group/golang-nuts">golang-nuts.

-

Checkins Mailing List

+

Checkins Mailing List

A mailing list that receives a message summarizing each checkin to the Go repository.

+

Bugs Mailing List

+

A mailing list that receives each update to the Go issue tracker.

+

Build Status

View the status of Go builds across the supported operating systems and architectures.

@@ -77,13 +81,13 @@ systems and architectures.

How you can help

-

Reporting issues

+

Reporting issues

If you spot bugs, mistakes, or inconsistencies in the Go project's code or documentation, please let us know by -filing a ticket -on our issue tracker. +filing a ticket +on our issue tracker. (Of course, you should check it's not an existing issue before creating a new one.)

@@ -102,8 +106,8 @@ To get started, read these contribution guidelines for information on design, testing, and our code review process.

-Check the tracker for +Check the tracker for open issues that interest you. Those labeled -HelpWanted +HelpWanted are particularly in need of outside help.

diff --git a/doc/contribute.html b/doc/contribute.html index 716a1849e..392734985 100644 --- a/doc/contribute.html +++ b/doc/contribute.html @@ -22,7 +22,7 @@ you're working on if you want it to become part of the main repository.

Before undertaking to write something new for the Go project, send -mail to the mailing +mail to the mailing list to discuss what you plan to do. This gives everyone a chance to validate the design, helps prevent duplication of effort, and ensures that the idea fits inside the goals for the language @@ -45,10 +45,14 @@ tree to make sure the changes don't break other packages or programs:

-cd $GOROOT/src
-./all.bash    # On Windows, run all.bat
+$ cd go/src
+$ ./all.bash
 
+

+(To build under Windows use all.bat.) +

+

After running for a while, the command should print "ALL TESTS PASSED".

@@ -95,11 +99,11 @@ command.

Configure the extension

-

Edit $GOROOT/.hg/hgrc to add:

+

Edit .hg/hgrc in the root of your Go checkout to add:

 [extensions]
-codereview = $GOROOT/lib/codereview/codereview.py
+codereview = /path/to/go/lib/codereview/codereview.py
 
 [ui]
 username = Your Name <you@server.dom>
@@ -110,6 +114,16 @@ The username information will not be used unless
 you are a committer (see below), but Mercurial complains if it is missing.
 

+

+As the codereview extension is only enabled for your Go checkout, the remainder of this document assumes you +are inside the go directory when issuing commands. +

+ +

To contribute to subrepositories, edit the .hg/hgrc for each +subrepository in the same way. For example, add the codereview extension to +code.google.com/p/go.tools/.hg/hgrc. +

+

Understanding the extension

After adding the code review extension, you can run

@@ -126,16 +140,10 @@ $ hg help change

-As the codereview extension is only enabled for your checkout -in $GOROOT, the remainder of this document assumes you -are inside $GOROOT when issuing commands. -

- -

-Windows users may need to perform extra steps to get the code review +Windows users may need to perform extra steps to get the code review extension working. See the -CodeReview page -on the Go Wiki for details. +CodeReview page +on the Go Wiki for details.

Log in to the code review site.

@@ -146,7 +154,7 @@ The code review server uses a Google Account to authenticate. sign in at google.com, you can use it to sign in to the code review server.) The email address you use on the Code Review site -will be recorded in the Mercurial change log +will be recorded in the Mercurial change log and in the CONTRIBUTORS file. You can create a Google Account associated with any address where you receive email. @@ -155,7 +163,6 @@ application-specific password and use that when prompted for a password.

-$ cd $GOROOT
 $ hg code-login
 Email (login for uploading to codereview.appspot.com): rsc@golang.org
 Password for rsc@golang.org:
@@ -165,7 +172,7 @@ Saving authentication cookies to /Users/rsc/.codereview_upload_cookies_coderevie
 
 

Configure your account settings.

-

Edit your code review settings. +

Edit your code review settings. Grab a nickname. Many people prefer to set the Context option to “Whole file” to see more context when reviewing changes. @@ -240,7 +247,7 @@ These can be code review nicknames or arbitrary email addresses. Unless explicitly told otherwise, such as in the discussion leading up to sending in the change list, leave the reviewer field blank. This means that the -golang-dev@googlegroups.com +golang-codereviews@googlegroups.com mailing list will be used as the reviewer.

@@ -270,7 +277,7 @@ After editing, the template might now read: # Lines beginning with # are ignored. # Multi-line values should be indented. -Reviewer: golang-dev@googlegroups.com +Reviewer: golang-codereviews@googlegroups.com CC: math-nuts@swtch.com Description: @@ -286,11 +293,11 @@ Files:

The special sentence “Fixes issue 159.” associates -the change with issue 159 in the Go issue tracker. +the change with issue 159 in the Go issue tracker. When this change is eventually submitted, the issue tracker will automatically mark the issue as fixed. (These conventions are described in detail by the -Google Project Hosting Issue Tracker documentation.) +Google Project Hosting Issue Tracker documentation.)

@@ -302,7 +309,7 @@ which hg change will print, something like:

-CL created: http://codereview.appspot.com/99999
+CL created: https://codereview.appspot.com/99999
 

Adding or removing files from an existing change

@@ -448,7 +455,7 @@ lines blank and then run:

-$ hg mail -r golang-dev@googlegroups.com --cc math-nuts@swtch.com 99999
+$ hg mail -r golang-codereviews@googlegroups.com --cc math-nuts@swtch.com 99999
 

to achieve the same effect.

@@ -473,31 +480,33 @@ to send comments back.

Revise and upload

-You will probably revise your code in response to the reviewer comments. When -you have done this, you can upload your change to the code review server -without sending a notification by running hg upload using the change -list number assigned during hg change +When you have revised the code and are ready for another round of review, +you can upload your change and send mail asking the reviewers to +please take another look (PTAL). Use the change list number +assigned during hg change

-$ hg upload 99999
+$ hg mail 99999
 
+

-When you have revised the code and are ready for another round of review, run +Or to upload your change without sending a notification, run

-$ hg mail 99999
+$ hg upload 99999
 
-

again to upload the latest copy and send mail asking the reviewers to please take another look -(PTAL). +

+You will probably revise your code in response to the reviewer comments. You might also visit the code review web page and reply to the comments, letting the reviewer know that you've addressed them or explain why you haven't. When you're done replying, click “Publish and Mail comments” to send the line-by-line replies and any other comments.

+

The reviewer can comment on the new copy, and the process repeats. The reviewer approves the change by replying with a mail that says @@ -597,11 +606,18 @@ $ hg submit 99999 local repository out of date; must sync before submit

+

More information

+ +

+In addition to the information here, the Go community maintains a CodeReview wiki page. +Feel free to contribute to this page as you learn the review process. +

+

Files in the Go repository don't list author names, both to avoid clutter and to avoid having to keep the lists up to date. -Instead, your name will appear in the Mercurial change log +Instead, your name will appear in the Mercurial change log and in the CONTRIBUTORS file and perhaps the AUTHORS file.

@@ -616,13 +632,15 @@ In order for them to do that, you need to have completed one of the contributor license agreements:
  • -If you are the copyright holder, you will need to agree to -the individual +If you are the copyright holder, you will need to agree to the +individual contributor license agreement, which can be completed online.
  • If your organization is the copyright holder, the organization -will need to agree to the corporate contributor license agreement. +will need to agree to the +corporate +contributor license agreement. (If the copyright holder for your code has already completed the agreement in connection with another Google open source project, it does not need to be completed again.) @@ -636,7 +654,7 @@ This rigmarole needs to be done only for your first submission.

    Code that you contribute should use the standard copyright header:

    -// Copyright 2013 The Go Authors. All rights reserved.
    +// Copyright 2014 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.
     
    diff --git a/doc/debugging_with_gdb.html b/doc/debugging_with_gdb.html index b893f931a..afaedf74c 100644 --- a/doc/debugging_with_gdb.html +++ b/doc/debugging_with_gdb.html @@ -9,6 +9,23 @@ Besides this overview you might want to consult the GDB manual.

    +

    +GDB does not understand Go programs well. +The stack management, threading, and runtime contain aspects that differ +enough from the execution model GDB expects that they can confuse +the debugger, even when the program is compiled with gccgo. +As a consequence, although GDB can be useful in some situations, it is +not a reliable debugger for Go programs, particularly heavily concurrent ones. +Moreover, it is not a priority for the Go project to address these issues, which +are difficult. +In short, the instructions below should be taken only as a guide to how +to use GDB when it works, not as a guarantee of success. +

    + +

    +In time, a more Go-centric debugging architecture may be required. +

    +

    Introduction

    @@ -19,8 +36,8 @@ use to inspect a live process or a core dump.

    -Pass the '-s' flag to the linker to omit the debug information -(for example, go build -ldflags "-s" prog.go). +Pass the '-w' flag to the linker to omit the debug information +(for example, go build -ldflags "-w" prog.go).

    diff --git a/doc/devel/release.html b/doc/devel/release.html index 5511db71b..3a3d5bc13 100644 --- a/doc/devel/release.html +++ b/doc/devel/release.html @@ -13,12 +13,38 @@ hg pull hg update tag +

    go1.3 (released 2014/06/18)

    + +

    +Go 1.3 is a major release of Go. +Read the Go 1.3 Release Notes for more information. +

    + +

    go1.2 (released 2013/12/01)

    + +

    +Go 1.2 is a major release of Go. +Read the Go 1.2 Release Notes for more information. +

    + +

    Minor revisions

    + +

    +go1.2.1 (released 2014/03/02) includes bug fixes to the runtime, net, and database/sql packages. +See the change history for details. +

    + +

    +go1.2.2 (released 2014/05/05) includes a +security fix +that affects the tour binary included in the binary distributions (thanks to Guillaume T). +

    +

    go1.1 (released 2013/05/13)

    Go 1.1 is a major release of Go. -Read the Go 1.1 Release Notes for -more information. +Read the Go 1.1 Release Notes for more information.

    Minor revisions

    @@ -363,12 +389,6 @@ variable to build and install your own code and external libraries outside of the Go tree (and avoid writing Makefiles).

    -

    Minor revisions

    - -

    -go1.2.1 (released 2014/03/02) includes bug fixes to the runtime, net, and database/sql packages. -See the change history for details. -

    Minor revisions

    diff --git a/doc/docs.html b/doc/docs.html index 7aad8dadf..bb2d52dcb 100644 --- a/doc/docs.html +++ b/doc/docs.html @@ -97,6 +97,9 @@ one goroutine can be guaranteed to observe values produced by writes to the same variable in a different goroutine.

    +

    Release History

    +

    A summary of the changes between Go releases.

    +

    Articles

    @@ -143,7 +146,9 @@ Guided tours of Go programs.
  • Debugging Go Code with GDB
  • Godoc: documenting Go code - writing good documentation for godoc.
  • Profiling Go Programs
  • -
  • Data Race Detector - testing Go programs for race conditions.
  • +
  • Data Race Detector - a manual for the data race detector.
  • +
  • Introducing the Go Race Detector - an introduction to the race detector. +
  • A Quick Guide to Go's Assembler - an introduction to the assembler used by Go.

More

diff --git a/doc/effective_go.html b/doc/effective_go.html index f9199511a..25266d6ab 100644 --- a/doc/effective_go.html +++ b/doc/effective_go.html @@ -214,7 +214,7 @@ not be used. One adjustment godoc does do is to display indented text in a fixed-width font, suitable for program snippets. The package comment for the -fmt package uses this to good effect. +fmt package uses this to good effect.

@@ -288,7 +288,7 @@ var (

-Even for private names, grouping can also indicate relationships between items, +Grouping can also indicate relationships between items, such as the fact that a set of variables is protected by a mutex.

@@ -350,7 +350,7 @@ not encoding_base64 and not encodingBase64.

-The importer of a package will use the name to refer to its contents. +The importer of a package will use the name to refer to its contents, so exported names in the package can use that fact to avoid stutter. (Don't use the import . notation, which can simplify @@ -701,6 +701,7 @@ for _, value := range array {

The blank identifier has many uses, as described in a later section. +

For strings, the range does more work for you, breaking out individual @@ -709,7 +710,7 @@ Erroneous encodings consume one byte and produce the replacement rune U+FFFD. (The name (with associated builtin type) rune is Go terminology for a single Unicode code point. -See the language specification +See the language specification for details.) The loop

@@ -849,7 +850,7 @@ func Compare(a, b []byte) int { } -

Type switch

+

Type switch

A switch can also be used to discover the dynamic type of an interface @@ -1385,8 +1386,9 @@ func (file *File) Read(buf []byte) (n int, err error)

The method returns the number of bytes read and an error value, if -any. To read into the first 32 bytes of a larger buffer -b, slice (here used as a verb) the buffer. +any. +To read into the first 32 bytes of a larger buffer +buf, slice (here used as a verb) the buffer.

     n, err := f.Read(buf[0:32])
@@ -1487,7 +1489,7 @@ If the slices might grow or shrink, they should be allocated independently
 to avoid overwriting the next line; if not, it can be more efficient to construct
 the object with a single allocation.
 For reference, here are sketches of the two methods.
-First, a line a time:
+First, a line at a time:
 

@@ -2054,10 +2056,22 @@ We pass the address of a ByteSlice
 because only *ByteSlice satisfies io.Writer.
 The rule about pointers vs. values for receivers is that value methods
 can be invoked on pointers and values, but pointer methods can only be
-invoked on pointers.  This is because pointer methods can modify the
-receiver; invoking them on a copy of the value would cause those
-modifications to be discarded.
+invoked on pointers.
 

+ +

+This rule arises because pointer methods can modify the receiver; invoking +them on a value would cause the method to receive a copy of the value, so +any modifications would be discarded. +The language therefore disallows this mistake. +There is a handy exception, though. When the value is addressable, the +language takes care of the common case of invoking a pointer method on a +value by inserting the address operator automatically. +In our example, the variable b is addressable, so we can call +its Write method with just b.Write. The compiler +will rewrite that to (&b).Write for us. +

+

By the way, the idea of using Write on a slice of bytes is central to the implementation of bytes.Buffer. @@ -2173,6 +2187,7 @@ A one-case type switch would do, but so would a type assertion. A type assertion takes an interface value and extracts from it a value of the specified explicit type. The syntax borrows from the clause opening a type switch, but with an explicit type rather than the type keyword: +

 value.(typeName)
@@ -2463,6 +2478,8 @@ It has uses beyond those we've seen already.
 

The use of a blank identifier in a for range loop is a special case of a general situation: multiple assignment. +

+

If an assignment requires multiple values on the left side, but one of the values will not be used by the program, @@ -2937,26 +2954,19 @@ means waiting until some receiver has retrieved a value.

A buffered channel can be used like a semaphore, for instance to limit throughput. In this example, incoming requests are passed -to handle, which receives a value from the channel, processes -the request, and then sends a value back to the channel -to ready the "semaphore" for the next consumer. +to handle, which sends a value into the channel, processes +the request, and then receives a value from the channel +to ready the “semaphore” for the next consumer. The capacity of the channel buffer limits the number of -simultaneous calls to process, -so during initialization we prime the channel by filling it to capacity. +simultaneous calls to process.

 var sem = make(chan int, MaxOutstanding)
 
 func handle(r *Request) {
-    <-sem          // Wait for active queue to drain.
-    process(r)     // May take a long time.
-    sem <- 1       // Done; enable next request to run.
-}
-
-func init() {
-    for i := 0; i < MaxOutstanding; i++ {
-        sem <- 1
-    }
+    sem <- 1    // Wait for active queue to drain.
+    process(r)  // May take a long time.
+    <-sem       // Done; enable next request to run.
 }
 
 func Serve(queue chan *Request) {
@@ -2968,10 +2978,9 @@ func Serve(queue chan *Request) {
 

-Because data synchronization occurs on a receive from a channel -(that is, the send "happens before" the receive; see -The Go Memory Model), -acquisition of the semaphore must be on a channel receive, not a send. +Once MaxOutstanding handlers are executing process, +any more will block trying to send into the filled channel buffer, +until one of the existing handlers finishes and receives from the buffer.

@@ -2988,10 +2997,10 @@ Here's an obvious solution, but beware it has a bug we'll fix subsequently:

 func Serve(queue chan *Request) {
     for req := range queue {
-        <-sem
+        sem <- 1
         go func() {
             process(req) // Buggy; see explanation below.
-            sem <- 1
+            <-sem
         }()
     }
 }
@@ -3009,10 +3018,10 @@ to the closure in the goroutine:
 func Serve(queue chan *Request) {
     for req := range queue {
-        <-sem
+        sem <- 1
         go func(req *Request) {
             process(req)
-            sem <- 1
+            <-sem
         }(req)
     }
 }
@@ -3027,11 +3036,11 @@ name, as in this example:
 func Serve(queue chan *Request) {
     for req := range queue {
-        <-sem
         req := req // Create new instance of req for the goroutine.
+        sem <- 1
         go func() {
             process(req)
-            sem <- 1
+            <-sem
         }()
     }
 }
@@ -3278,9 +3287,18 @@ the garbage collector for bookkeeping.

Library routines must often return some sort of error indication to -the caller. As mentioned earlier, Go's multivalue return makes it +the caller. +As mentioned earlier, Go's multivalue return makes it easy to return a detailed error description alongside the normal -return value. By convention, errors have type error, +return value. +It is good style to use this feature to provide detailed error information. +For example, as we'll see, os.Open doesn't +just return a nil pointer on failure, it also returns an +error value that describes what went wrong. +

+ +

+By convention, errors have type error, a simple built-in interface.

@@ -3292,7 +3310,12 @@ type error interface {
 A library writer is free to implement this interface with a
 richer model under the covers, making it possible not only
 to see the error but also to provide some context.
-For example, os.Open returns an os.PathError.
+As mentioned, alongside the usual *os.File
+return value, os.Open also returns an
+error value.
+If the file is opened successfully, the error will be nil,
+but when there is a problem, it will hold an
+os.PathError:
 

 // PathError records an error and the operation and
diff --git a/doc/gccgo_install.html b/doc/gccgo_install.html
index eef5ac220..4c1a8c2f5 100644
--- a/doc/gccgo_install.html
+++ b/doc/gccgo_install.html
@@ -291,9 +291,9 @@ first one that it finds.
 
 
  • FILE.gox -
  • FILE.o
  • libFILE.so
  • libFILE.a +
  • FILE.o

@@ -522,4 +522,4 @@ port is for x86. The goal is to extend the port to most of the architectures supported by RTEMS. For more information on the port, as well as instructions on how to install it, please see this -RTEMS Wiki page. +RTEMS Wiki page. diff --git a/doc/go1.3.html b/doc/go1.3.html new file mode 100644 index 000000000..ae5c02598 --- /dev/null +++ b/doc/go1.3.html @@ -0,0 +1,599 @@ + + +

Introduction to Go 1.3

+ +

+The latest Go release, version 1.3, arrives six months after 1.2, +and contains no language changes. +It focuses primarily on implementation work, providing +precise garbage collection, +a major refactoring of the compiler tool chain that results in +faster builds, especially for large projects, +significant performance improvements across the board, +and support for DragonFly BSD, Solaris, Plan 9 and Google's Native Client architecture (NaCl). +It also has an important refinement to the memory model regarding synchronization. +As always, Go 1.3 keeps the promise +of compatibility, +and almost everything +will continue to compile and run without change when moved to 1.3. +

+ +

Changes to the supported operating systems and architectures

+ +

Removal of support for Windows 2000

+ +

+Microsoft stopped supporting Windows 2000 in 2010. +Since it has implementation difficulties +regarding exception handling (signals in Unix terminology), +as of Go 1.3 it is not supported by Go either. +

+ +

Support for DragonFly BSD

+ +

+Go 1.3 now includes experimental support for DragonFly BSD on the amd64 (64-bit x86) and 386 (32-bit x86) architectures. +It uses DragonFly BSD 3.6 or above. +

+ +

Support for FreeBSD

+ +

+It was not announced at the time, but since the release of Go 1.2, support for Go on FreeBSD +requires FreeBSD 8 or above. +

+ +

+As of Go 1.3, support for Go on FreeBSD requires that the kernel be compiled with the +COMPAT_FREEBSD32 flag configured. +

+ +

+In concert with the switch to EABI syscalls for ARM platforms, Go 1.3 will run only on FreeBSD 10. +The x86 platforms, 386 and amd64, are unaffected. +

+ +

Support for Native Client

+ +

+Support for the Native Client virtual machine architecture has returned to Go with the 1.3 release. +It runs on the 32-bit Intel architectures (GOARCH=386) and also on 64-bit Intel, but using +32-bit pointers (GOARCH=amd64p32). +There is not yet support for Native Client on ARM. +Note that this is Native Client (NaCl), not Portable Native Client (PNaCl). +Details about Native Client are here; +how to set up the Go version is described here. +

+ +

Support for NetBSD

+ +

+As of Go 1.3, support for Go on NetBSD requires NetBSD 6.0 or above. +

+ +

Support for OpenBSD

+ +

+As of Go 1.3, support for Go on OpenBSD requires OpenBSD 5.5 or above. +

+ +

Support for Plan 9

+ +

+Go 1.3 now includes experimental support for Plan 9 on the 386 (32-bit x86) architecture. +It requires the Tsemacquire syscall, which has been in Plan 9 since June, 2012. +

+ +

Support for Solaris

+ +

+Go 1.3 now includes experimental support for Solaris on the amd64 (64-bit x86) architecture. +It requires illumos, Solaris 11 or above. +

+ +

Changes to the memory model

+ +

+The Go 1.3 memory model adds a new rule +concerning sending and receiving on buffered channels, +to make explicit that a buffered channel can be used as a simple +semaphore, using a send into the +channel to acquire and a receive from the channel to release. +This is not a language change, just a clarification about an expected property of communication. +

+ +

Changes to the implementations and tools

+ +

Stack

+ +

+Go 1.3 has changed the implementation of goroutine stacks away from the old, +"segmented" model to a contiguous model. +When a goroutine needs more stack +than is available, its stack is transferred to a larger single block of memory. +The overhead of this transfer operation amortizes well and eliminates the old "hot spot" +problem when a calculation repeatedly steps across a segment boundary. +Details including performance numbers are in this +design document. +

+ +

Changes to the garbage collector

+ +

+For a while now, the garbage collector has been precise when examining +values in the heap; the Go 1.3 release adds equivalent precision to values on the stack. +This means that a non-pointer Go value such as an integer will never be mistaken for a +pointer and prevent unused memory from being reclaimed. +

+ +

+Starting with Go 1.3, the runtime assumes that values with pointer type +contain pointers and other values do not. +This assumption is fundamental to the precise behavior of both stack expansion +and garbage collection. +Programs that use package unsafe +to store integers in pointer-typed values are illegal and will crash if the runtime detects the behavior. +Programs that use package unsafe to store pointers +in integer-typed values are also illegal but more difficult to diagnose during execution. +Because the pointers are hidden from the runtime, a stack expansion or garbage collection +may reclaim the memory they point at, creating +dangling pointers. +

+ +

+Updating: Code that uses unsafe.Pointer to convert +an integer-typed value held in memory into a pointer is illegal and must be rewritten. +Such code can be identified by go vet. +

+ +

Map iteration

+ +

+Iterations over small maps no longer happen in a consistent order. +Go 1 defines that “The iteration order over maps +is not specified and is not guaranteed to be the same from one iteration to the next.” +To keep code from depending on map iteration order, +Go 1.0 started each map iteration at a random index in the map. +A new map implementation introduced in Go 1.1 neglected to randomize +iteration for maps with eight or fewer entries, although the iteration order +can still vary from system to system. +This has allowed people to write Go 1.1 and Go 1.2 programs that +depend on small map iteration order and therefore only work reliably on certain systems. +Go 1.3 reintroduces random iteration for small maps in order to flush out these bugs. +

+ +

+Updating: If code assumes a fixed iteration order for small maps, +it will break and must be rewritten not to make that assumption. +Because only small maps are affected, the problem arises most often in tests. +

+ + + +

+As part of the general overhaul to +the Go linker, the compilers and linkers have been refactored. +The linker is still a C program, but now the instruction selection phase that +was part of the linker has been moved to the compiler through the creation of a new +library called liblink. +By doing instruction selection only once, when the package is first compiled, +this can speed up compilation of large projects significantly. +

+ +

+Updating: Although this is a major internal change, it should have no +effect on programs. +

+ +

Status of gccgo

+ +

+GCC release 4.9 will contain the Go 1.2 (not 1.3) version of gccgo. +The release schedules for the GCC and Go projects do not coincide, +which means that 1.3 will be available in the development branch but +that the next GCC release, 4.10, will likely have the Go 1.4 version of gccgo. +

+ +

Changes to the go command

+ +

+The cmd/go command has several new +features. +The go run and +go test subcommands +support a new -exec option to specify an alternate +way to run the resulting binary. +Its immediate purpose is to support NaCl. +

+ +

+The test coverage support of the go test +subcommand now automatically sets the coverage mode to -atomic +when the race detector is enabled, to eliminate false reports about unsafe +access to coverage counters. +

+ +

+The go test subcommand +now always builds the package, even if it has no test files. +Previously, it would do nothing if no test files were present. +

+ +

+The go build subcommand +supports a new -i option to install dependencies +of the specified target, but not the target itself. +

+ +

+Cross compiling with cgo enabled +is now supported. +The CC_FOR_TARGET and CXX_FOR_TARGET environment +variables are used when running all.bash to specify the cross compilers +for C and C++ code, respectively. +

+ +

+Finally, the go command now supports packages that import Objective-C +files (suffixed .m) through cgo. +

+ +

Changes to cgo

+ +

+The cmd/cgo command, +which processes import "C" declarations in Go packages, +has corrected a serious bug that may cause some packages to stop compiling. +Previously, all pointers to incomplete struct types translated to the Go type *[0]byte, +with the effect that the Go compiler could not diagnose passing one kind of struct pointer +to a function expecting another. +Go 1.3 corrects this mistake by translating each different +incomplete struct to a different named type. +

+ +

+Given the C declaration typedef struct S T for an incomplete struct S, +some Go code used this bug to refer to the types C.struct_S and C.T interchangeably. +Cgo now explicitly allows this use, even for completed struct types. +However, some Go code also used this bug to pass (for example) a *C.FILE +from one package to another. +This is not legal and no longer works: in general Go packages +should avoid exposing C types and names in their APIs. +

+ +

+Updating: Code confusing pointers to incomplete types or +passing them across package boundaries will no longer compile +and must be rewritten. +If the conversion is correct and must be preserved, +use an explicit conversion via unsafe.Pointer. +

+ +

SWIG 3.0 required for programs that use SWIG

+ +

+For Go programs that use SWIG, SWIG version 3.0 is now required. +The cmd/go command will now link the +SWIG generated object files directly into the binary, rather than +building and linking with a shared library. +

+ +

Command-line flag parsing

+ +

+In the gc tool chain, the assemblers now use the +same command-line flag parsing rules as the Go flag package, a departure +from the traditional Unix flag parsing. +This may affect scripts that invoke the tool directly. +For example, +go tool 6a -SDfoo must now be written +go tool 6a -S -D foo. +(The same change was made to the compilers and linkers in Go 1.1.) +

+ +

Changes to godoc

+

+When invoked with the -analysis flag, +godoc +now performs sophisticated static +analysis of the code it indexes. +The results of analysis are presented in both the source view and the +package documentation view, and include the call graph of each package +and the relationships between +definitions and references, +types and their methods, +interfaces and their implementations, +send and receive operations on channels, +functions and their callers, and +call sites and their callees. +

+ +

Miscellany

+ +

+The program misc/benchcmp that compares +performance across benchmarking runs has been rewritten. +Once a shell and awk script in the main repository, it is now a Go program in the go.tools repo. +Documentation is here. +

+ +

+For the few of us that build Go distributions, the tool misc/dist has been +moved and renamed; it now lives in misc/makerelease, still in the main repository. +

+ +

Performance

+ +

+The performance of Go binaries for this release has improved in many cases due to changes +in the runtime and garbage collection, plus some changes to libraries. +Significant instances include: +

+ +
    + +
  • +The runtime handles defers more efficiently, reducing the memory footprint by about two kilobytes +per goroutine that calls defer. +
  • + +
  • +The garbage collector has been sped up, using a concurrent sweep algorithm, +better parallelization, and larger pages. +The cumulative effect can be a 50-70% reduction in collector pause time. +
  • + +
  • +The race detector (see this guide) +is now about 40% faster. +
  • + +
  • +The regular expression package regexp +is now significantly faster for certain simple expressions due to the implementation of +a second, one-pass execution engine. +The choice of which engine to use is automatic; +the details are hidden from the user. +
  • + +
+ +

+Also, the runtime now includes in stack dumps how long a goroutine has been blocked, +which can be useful information when debugging deadlocks or performance issues. +

+ +

Changes to the standard library

+ +

New packages

+ +

+A new package debug/plan9obj was added to the standard library. +It implements access to Plan 9 a.out object files. +

+ +

Major changes to the library

+ +

+A previous bug in crypto/tls +made it possible to skip verification in TLS inadvertently. +In Go 1.3, the bug is fixed: one must specify either ServerName or +InsecureSkipVerify, and if ServerName is specified it is enforced. +This may break existing code that incorrectly depended on insecure +behavior. +

+ +

+There is an important new type added to the standard library: sync.Pool. +It provides an efficient mechanism for implementing certain types of caches whose memory +can be reclaimed automatically by the system. +

+ +

+The testing package's benchmarking helper, +B, now has a +RunParallel method +to make it easier to run benchmarks that exercise multiple CPUs. +

+ +

+Updating: The crypto/tls fix may break existing code, but such +code was erroneous and should be updated. +

+ +

Minor changes to the library

+ +

+The following list summarizes a number of minor changes to the library, mostly additions. +See the relevant package documentation for more information about each change. +

+ +
    + +
  • In the crypto/tls package, +a new DialWithDialer +function lets one establish a TLS connection using an existing dialer, making it easier +to control dial options such as timeouts. +The package also now reports the TLS version used by the connection in the +ConnectionState +struct. +
  • + +
  • The CreateCertificate +function of the crypto/tls package +now supports parsing (and elsewhere, serialization) of PKCS #10 certificate +signature requests. +
  • + +
  • +The formatted print functions of the fmt package now define %F +as a synonym for %f when printing floating-point values. +
  • + +
  • +The math/big package's +Int and +Rat types +now implement +encoding.TextMarshaler and +encoding.TextUnmarshaler. +
  • + +
  • +The complex power function, Pow, +now specifies the behavior when the first argument is zero. +It was undefined before. +The details are in the documentation for the function. +
  • + +
  • +The net/http package now exposes the +properties of a TLS connection used to make a client request in the new +Response.TLS field. +
  • + +
  • +The net/http package now +allows setting an optional server error logger +with Server.ErrorLog. +The default is still that all errors go to stderr. +
  • + +
  • +The net/http package now +supports disabling HTTP keep-alive connections on the server +with Server.SetKeepAlivesEnabled. +The default continues to be that the server does keep-alive (reuses +connections for multiple requests) by default. +Only resource-constrained servers or those in the process of graceful +shutdown will want to disable them. +
  • + +
  • +The net/http package adds an optional +Transport.TLSHandshakeTimeout +setting to cap the amount of time HTTP client requests will wait for +TLS handshakes to complete. +It's now also set by default +on DefaultTransport. +
  • + +
  • +The net/http package's +DefaultTransport, +used by the HTTP client code, now +enables TCP +keep-alives by default. +Other Transport +values with a nil Dial field continue to function the same +as before: no TCP keep-alives are used. +
  • + +
  • +The net/http package +now enables TCP +keep-alives for incoming server requests when +ListenAndServe +or +ListenAndServeTLS +are used. +When a server is started otherwise, TCP keep-alives are not enabled. +
  • + +
  • +The net/http package now +provides an +optional Server.ConnState +callback to hook various phases of a server connection's lifecycle +(see ConnState). +This can be used to implement rate limiting or graceful shutdown. +
  • + +
  • +The net/http package's HTTP +client now has an +optional Client.Timeout +field to specify an end-to-end timeout on requests made using the +client. +
  • + +
  • In the net package, +the Dialer struct now +has a KeepAlive option to specify a keep-alive period for the connection. +
  • + +
  • +The net/http package's +Transport +now closes Request.Body +consistently, even on error. +
  • + +
  • +The os/exec package now implements +what the documentation has always said with regard to relative paths for the binary. +In particular, it only calls LookPath +when the binary's file name contains no path separators. +
  • + +
  • +The SetMapIndex +function in the reflect package +no longer panics when deleting from a nil map. +
  • + +
  • +If the main goroutine calls +runtime.Goexit +and all other goroutines finish execution, the program now always crashes, +reporting a detected deadlock. +Earlier versions of Go handled this situation inconsistently: most instances +were reported as deadlocks, but some trivial cases exited cleanly instead. +
  • + +
  • +The runtime/debug package now has a new function +debug.WriteHeapDump +that writes out a description of the heap. +
  • + +
  • +The CanBackquote +function in the strconv package +now considers the DEL character, U+007F, to be +non-printing. +
  • + +
  • +The syscall package now provides +SendmsgN +as an alternate version of +Sendmsg +that returns the number of bytes written. +
  • + +
  • +On Windows, the syscall package now +supports the cdecl calling convention through the addition of a new function +NewCallbackCDecl +alongside the existing function +NewCallback. +
  • + +
  • +The testing package now +diagnoses tests that call panic(nil), which are almost always erroneous. +Also, tests now write profiles (if invoked with profiling flags) even on failure. +
  • + +
  • +The unicode package and associated +support throughout the system has been upgraded from +Unicode 6.2.0 to Unicode 6.3.0. +
  • + +
diff --git a/doc/go1.html b/doc/go1.html index 3bbe5d316..a664b6555 100644 --- a/doc/go1.html +++ b/doc/go1.html @@ -2035,4 +2035,4 @@ They are available for many combinations of architecture and operating system Installation details are described on the Getting Started page, while the distributions themselves are listed on the -downloads page. +downloads page. diff --git a/doc/go_faq.html b/doc/go_faq.html index f65dff796..b1945dda8 100644 --- a/doc/go_faq.html +++ b/doc/go_faq.html @@ -426,18 +426,20 @@ When a coroutine blocks, such as by calling a blocking system call, the run-time automatically moves other coroutines on the same operating system thread to a different, runnable thread so they won't be blocked. The programmer sees none of this, which is the point. -The result, which we call goroutines, can be very cheap: unless they spend a lot of time -in long-running system calls, they cost little more than the memory -for the stack, which is just a few kilobytes. +The result, which we call goroutines, can be very cheap: they have little +overhead beyond the memory for the stack, which is just a few kilobytes.

-To make the stacks small, Go's run-time uses segmented stacks. A newly +To make the stacks small, Go's run-time uses resizable, bounded stacks. A newly minted goroutine is given a few kilobytes, which is almost always enough. -When it isn't, the run-time allocates (and frees) extension segments automatically. -The overhead averages about three cheap instructions per function call. +When it isn't, the run-time grows (and shrinks) the memory for storing +the stack automatically, allowing many goroutines to live in a modest +amount of memory. +The CPU overhead averages about three cheap instructions per function call. It is practical to create hundreds of thousands of goroutines in the same -address space. If goroutines were just threads, system resources would +address space. +If goroutines were just threads, system resources would run out at a much smaller number.

@@ -446,7 +448,7 @@ Why are map operations not defined to be atomic?

After long discussion it was decided that the typical use of maps did not require -safe access from multiple threads, and in those cases where it did, the map was +safe access from multiple goroutines, and in those cases where it did, the map was probably part of some larger data structure or computation that was already synchronized. Therefore requiring that all map operations grab a mutex would slow down most programs and add safety to few. This was not an easy decision, @@ -938,9 +940,9 @@ How are libraries documented? There is a program, godoc, written in Go, that extracts package documentation from the source code. It can be used on the command line or on the web. An instance is running at -http://golang.org/pkg/. +http://golang.org/pkg/. In fact, godoc implements the full site at -http://golang.org/. +http://golang.org/.

@@ -957,6 +959,14 @@ compendium of do's and don'ts that allows interpretation. All the Go code in the repository has been run through gofmt.

+

+The document titled +Go Code Review Comments +is a collection of very short essays about details of Go idiom that are often +missed by programmers. +It is a handy reference for people doing code reviews for Go projects. +

+

How do I submit patches to the Go libraries?

@@ -1427,7 +1437,7 @@ each closure shares that single variable. When the closure runs, it prints the value of v at the time fmt.Println is executed, but v may have been modified since the goroutine was launched. To help detect this and other problems before they happen, run -go vet. +go vet.

@@ -1606,9 +1616,10 @@ it now. Gccgo's run-time support uses glibc. Gc uses a custom library to keep the footprint under control; it is compiled with a version of the Plan 9 C compiler that supports -segmented stacks for goroutines. -The gccgo compiler implements segmented -stacks on Linux only, supported by recent modifications to the gold linker. +resizable stacks for goroutines. +The gccgo compiler implements these on Linux only, +using a technique called segmented stacks, +supported by recent modifications to the gold linker.

diff --git a/doc/go_mem.html b/doc/go_mem.html index 3e769daec..2ea1ded7a 100644 --- a/doc/go_mem.html +++ b/doc/go_mem.html @@ -1,6 +1,6 @@ @@ -274,6 +274,41 @@ then the program would not be guaranteed to print crash, or do something else.)

+

+The kth receive on a channel with capacity C happens before the k+Cth send from that channel completes. +

+ +

+This rule generalizes the previous rule to buffered channels. +It allows a counting semaphore to be modeled by a buffered channel: +the number of items in the channel corresponds to the number of active uses, +the capacity of the channel corresponds to the maximum number of simultaneous uses, +sending an item acquires the semaphore, and receiving an item releases +the semaphore. +This is a common idiom for limiting concurrency. +

+ +

+This program starts a goroutine for every entry in the work list, but the +goroutines coordinate using the limit channel to ensure +that at most three are running work functions at a time. +

+ +
+var limit = make(chan int, 3)
+
+func main() {
+	for _, w := range work {
+		go func() {
+			limit <- 1
+			w()
+			<-limit
+		}()
+	}
+	select{}
+}
+
+

Locks

diff --git a/doc/go_spec.html b/doc/go_spec.html index bc9ec682a..baa0ecf40 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,6 +1,6 @@ @@ -23,7 +23,7 @@ TODO

This is a reference manual for the Go programming language. For -more information and other documents, see http://golang.org. +more information and other documents, see http://golang.org.

@@ -120,7 +120,7 @@ unicode_digit = /* a Unicode code point classified as "Decimal Digit" */ .

-In The Unicode Standard 6.2, +In The Unicode Standard 6.3, Section 4.5 "General Category" defines a set of character categories. Go treats those characters in category Lu, Ll, Lt, Lm, or Lo as Unicode letters, @@ -471,7 +471,7 @@ string composed of the uninterpreted (implicitly UTF-8-encoded) characters between the quotes; in particular, backslashes have no special meaning and the string may contain newlines. -Carriage returns inside raw string literals +Carriage return characters ('\r') inside raw string literals are discarded from the raw string value.

@@ -674,7 +674,8 @@ types, the dynamic type is always the static type.

Each type T has an underlying type: If T -is a predeclared type or a type literal, the corresponding underlying +is one of the predeclared boolean, numeric, or string types, or a type literal, +the corresponding underlying type is T itself. Otherwise, T's underlying type is the underlying type of the type to which T refers in its type declaration. @@ -695,19 +696,19 @@ and T4 is []T1.

Method sets

-A type may have a method set associated with it -(§Interface types, §Method declarations). +A type may have a method set associated with it. The method set of an interface type is its interface. -The method set of any other type T -consists of all methods with receiver type T. -The method set of the corresponding pointer type *T -is the set of all methods with receiver *T or T +The method set of any other type T consists of all +methods declared with receiver type T. +The method set of the corresponding pointer type *T +is the set of all methods declared with receiver *T or T (that is, it also contains the method set of T). Further rules apply to structs containing anonymous fields, as described in the section on struct types. Any other type has an empty method set. In a method set, each method must have a -unique method name. +unique +non-blank method name.

@@ -817,8 +818,8 @@ ElementType = Type .

-The length is part of the array's type; it must evaluate to a non- -negative constant representable by a value +The length is part of the array's type; it must evaluate to a +non-negative constant representable by a value of type int. The length of array a can be discovered using the built-in function len. @@ -1009,7 +1010,7 @@ A field declaration may be followed by an optional string literal tag, which becomes an attribute for all the fields in the corresponding field declaration. The tags are made visible through a reflection interface -and take part in type identity for structs +and take part in type identity for structs but are otherwise ignored.

@@ -1108,7 +1109,8 @@ InterfaceTypeName = TypeName .

As with all method sets, in an interface type, each method must have a -unique name. +unique +non-blank name.

@@ -1277,20 +1279,23 @@ may be added.
 

Channel types

-A channel provides a mechanism for two concurrently executing functions -to synchronize execution and communicate by passing a value of a -specified element type. +A channel provides a mechanism for +concurrently executing functions +to communicate by +sending and +receiving +values of a specified element type. The value of an uninitialized channel is nil.

-ChannelType = ( "chan" [ "<-" ] | "<-" "chan" ) ElementType .
+ChannelType = ( "chan" | "chan" "<-" | "<-" "chan" ) ElementType .
 

-The <- operator specifies the channel direction, +The optional <- operator specifies the channel direction, send or receive. If no direction is given, the channel is -bi-directional. +bidirectional. A channel may be constrained only to send or only to receive by conversion or assignment.

@@ -1317,7 +1322,7 @@ chan (<-chan int) A new, initialized channel value can be made using the built-in function make, -which takes the channel type and an optional capacity as arguments: +which takes the channel type and an optional capacity as arguments:

@@ -1325,21 +1330,35 @@ make(chan int, 100)
 

-The capacity, in number of elements, sets the size of the buffer in the channel. If the -capacity is greater than zero, the channel is asynchronous: communication operations -succeed without blocking if the buffer is not full (sends) or not empty (receives), -and elements are received in the order they are sent. -If the capacity is zero or absent, the communication succeeds only when both a sender and -receiver are ready. +The capacity, in number of elements, sets the size of the buffer in the channel. +If the capacity is zero or absent, the channel is unbuffered and communication +succeeds only when both a sender and receiver are ready. Otherwise, the channel +is buffered and communication succeeds without blocking if the buffer +is not full (sends) or not empty (receives). A nil channel is never ready for communication.

A channel may be closed with the built-in function -close; the -multi-valued assignment form of the +close. +The multi-valued assignment form of the receive operator -tests whether a channel has been closed. +reports whether a received value was sent before +the channel was closed. +

+ +

+A single channel may be used in +send statements, +receive operations, +and calls to the built-in functions +cap and +len +by any number of goroutines without further synchronization. +Channels act as first-in-first-out queues. +For example, if one goroutine sends values on a channel +and a second goroutine receives them, the values are +received in the order sent.

Properties of types and values

@@ -1515,6 +1534,9 @@ no identifier may be declared in both the file and package block.

The blank identifier may be used like any other identifier in a declaration, but it does not introduce a binding and thus is not declared. +In the package block, the identifier init may only be used for +init function declarations, +and like the blank identifier it does not introduce a new binding.

@@ -1770,9 +1792,9 @@ last non-empty expression list.
 
 

A type declaration binds an identifier, the type name, to a new type -that has the same underlying type as -an existing type. The new type is different from -the existing type. +that has the same underlying type as an existing type, +and operations defined for the existing type are also defined for the new type. +The new type is different from the existing type.

@@ -2267,8 +2289,6 @@ Similarly, elements that are addresses of composite literals may elide
 the &T when the element type is *T.
 

- -
 [...]Point{{1.5, -3.5}, {0, 0}}   // same as [...]Point{Point{1.5, -3.5}, Point{0, 0}}
 [][]int{{1, 2, 3}, {4, 5}}        // same as [][]int{[]int{1, 2, 3}, []int{4, 5}}
@@ -2278,13 +2298,13 @@ the &T when the element type is *T.
 
 

A parsing ambiguity arises when a composite literal using the -TypeName form of the LiteralType appears between the -keyword and the opening brace of the block of an -"if", "for", or "switch" statement, because the braces surrounding -the expressions in the literal are confused with those introducing -the block of statements. To resolve the ambiguity in this rare case, -the composite literal must appear within -parentheses. +TypeName form of the LiteralType appears as an operand between the +keyword and the opening brace of the block +of an "if", "for", or "switch" statement, and the composite literal +is not enclosed in parentheses, square brackets, or curly braces. +In this rare case, the opening brace of the literal is erroneously parsed +as the one introducing the block of statements. To resolve the ambiguity, +the composite literal must appear within parentheses.

@@ -2692,7 +2712,7 @@ For arrays or strings, the indices are in range if
 otherwise they are out of range.
 For slices, the upper index bound is the slice capacity cap(a) rather than the length.
 A constant index must be non-negative and representable by a value of type
-int.
+int; for arrays or constant strings, constant indices must also be in range.
 If both indices are constant, they must satisfy low <= high.
 If the indices are out of range at run time, a run-time panic occurs.
 

@@ -2752,7 +2772,7 @@ If the sliced operand is an array, it must be addre The indices are in range if 0 <= low <= high <= max <= cap(a), otherwise they are out of range. A constant index must be non-negative and representable by a value of type -int. +int; for arrays, constant indices must also be in range. If multiple indices are constant, the constants that are present must be in range relative to each other. If the indices are out of range at run time, a run-time panic occurs. @@ -2916,27 +2936,32 @@ There is no distinct method type and there are no method literals.

Passing arguments to ... parameters

-If f is variadic with final parameter type ...T, -then within the function the argument is equivalent to a parameter of type -[]T. At each call of f, the argument -passed to the final parameter is -a new slice of type []T whose successive elements are -the actual arguments, which all must be assignable -to the type T. The length of the slice is therefore the number of -arguments bound to the final parameter and may differ for each call site. +If f is variadic with a final +parameter p of type ...T, then within f +the type of p is equivalent to type []T. +If f is invoked with no actual arguments for p, +the value passed to p is nil. +Otherwise, the value passed is a new slice +of type []T with a new underlying array whose successive elements +are the actual arguments, which all must be assignable +to T. The length and capacity of the slice is therefore +the number of arguments bound to p and may differ for each +call site.

-Given the function and call +Given the function and calls

 func Greeting(prefix string, who ...string)
+Greeting("nobody")
 Greeting("hello:", "Joe", "Anna", "Eileen")
 

within Greeting, who will have the value -[]string{"Joe", "Anna", "Eileen"} +nil in the first call, and +[]string{"Joe", "Anna", "Eileen"} in the second.

@@ -3385,7 +3410,8 @@ and the type of the receive operation is the element type of the channel. The expression blocks until a value is available. Receiving from a nil channel blocks forever. A receive operation on a closed channel can always proceed -immediately, yielding the element type's zero value. +immediately, yielding the element type's zero value +after any previously sent values have been received.

@@ -3929,7 +3955,7 @@ an untyped complex constant.
 
 
 const ic = complex(0, c)   // ic == 3.75i  (untyped complex constant)
-const iΘ = complex(0, Θ)   // iΘ == 1.5i   (type complex128)
+const iΘ = complex(0, Θ)   // iΘ == 1i     (type complex128)
 

@@ -3992,8 +4018,11 @@ precision.

Order of evaluation

-When evaluating the operands of an expression, -assignment, or +At package level, initialization dependencies +determine the evaluation order of individual initialization expressions in +variable declarations. +Otherwise, when evaluating the operands of an +expression, assignment, or return statement, all function calls, method calls, and communication operations are evaluated in lexical left-to-right @@ -4001,7 +4030,7 @@ order.

-For example, in the assignment +For example, in the (function-local) assignment

 y[f()], ok = g(h(), i()+x[j()], <-c), k()
@@ -4018,11 +4047,33 @@ of y is not specified.
 
 a := 1
 f := func() int { a++; return a }
-x := []int{a, f()} // x may be [1, 2] or [2, 2]: evaluation order between a and f() is not specified
-m := map[int]int{a: 1, a: 2} // m may be {2: 1} or {2: 2}: evaluation order between the two map assignments is not specified
-m2 := map[int]int{a: f()} // m2 may be {2: 3} or {3: 3}: evaluation order between the key and the value is not specified
+x := []int{a, f()}            // x may be [1, 2] or [2, 2]: evaluation order between a and f() is not specified
+m := map[int]int{a: 1, a: 2}  // m may be {2: 1} or {2: 2}: evaluation order between the two map assignments is not specified
+n := map[int]int{a: f()}      // n may be {2: 3} or {3: 3}: evaluation order between the key and the value is not specified
 
+

+At package level, initialization dependencies override the left-to-right rule +for individual initialization expressions, but not for operands within each +expression: +

+ +
+var a, b, c = f() + v(), g(), sqr(u()) + v()
+
+func f() int        { return c }
+func g() int        { return a }
+func sqr(x int) int { return x*x }
+
+// functions u and v are independent of all other variables and functions
+
+ +

+The function calls happen in the order +u(), sqr(), v(), +f(), v(), and g(). +

+

Floating-point operations within a single expression are evaluated according to the associativity of the operators. Explicit parentheses affect the evaluation @@ -4209,22 +4260,8 @@ A send on a closed channel proceeds by causing a run- A send on a nil channel blocks forever.

-

-Channels act as first-in-first-out queues. -For example, if a single goroutine sends on a channel values -that are received by a single goroutine, the values are received in the order sent. -

- -

-A single channel may be used for send and receive -operations and calls to the built-in functions -cap and -len -by any number of goroutines without further synchronization. -

-
-ch <- 3
+ch <- 3  // send value 3 to channel ch
 
@@ -4459,8 +4496,8 @@ If no case matches and there is a "default" case, its statements are executed. There can be at most one default case and it may appear anywhere in the "switch" statement. -A missing switch expression is equivalent to -the expression true. +A missing switch expression is equivalent to the boolean value +true.

@@ -4625,7 +4662,8 @@ Condition = Expression .
 In its simplest form, a "for" statement specifies the repeated execution of
 a block as long as a boolean condition evaluates to true.
 The condition is evaluated before each iteration.
-If the condition is absent, it is equivalent to true.
+If the condition is absent, it is equivalent to the boolean value
+true.
 

@@ -4662,7 +4700,8 @@ only if the block was executed).
 Any element of the ForClause may be empty but the
 semicolons are
 required unless there is only a condition.
-If the condition is absent, it is equivalent to true.
+If the condition is absent, it is equivalent to the boolean value
+true.
 

@@ -4844,8 +4883,12 @@ go func(ch chan<- bool) { for { sleep(10); ch <- true; }} (c)
 

Select statements

-A "select" statement chooses which of a set of possible communications -will proceed. It looks similar to a "switch" statement but with the +A "select" statement chooses which of a set of possible +send or +receive +operations will proceed. +It looks similar to a +"switch" statement but with the cases all referring to communication operations.

@@ -4858,41 +4901,63 @@ RecvExpr = Expression .

-RecvExpr must be a receive operation. -For all the cases in the "select" -statement, the channel expressions are evaluated in top-to-bottom order, along with -any expressions that appear on the right hand side of send statements. -A channel may be nil, -which is equivalent to that case not -being present in the select statement -except, if a send, its expression is still evaluated. -If any of the resulting operations can proceed, one of those is -chosen and the corresponding communication and statements are -evaluated. Otherwise, if there is a default case, that executes; -if there is no default case, the statement blocks until one of the communications can -complete. There can be at most one default case and it may appear anywhere in the -"select" statement. -If there are no cases with non-nil channels, -the statement blocks forever. -Even if the statement blocks, -the channel and send expressions are evaluated only once, -upon entering the select statement. +A case with a RecvStmt may assign the result of a RecvExpr to one or +two variables, which may be declared using a +short variable declaration. +The RecvExpr must be a (possibly parenthesized) receive operation. +There can be at most one default case and it may appear anywhere +in the list of cases.

+

-Since all the channels and send expressions are evaluated, any side -effects in that evaluation will occur for all the communications -in the "select" statement. +Execution of a "select" statement proceeds in several steps:

+ +
    +
  1. +For all the cases in the statement, the channel operands of receive operations +and the channel and right-hand-side expressions of send statements are +evaluated exactly once, in source order, upon entering the "select" statement. +The result is a set of channels to receive from or send to, +and the corresponding values to send. +Any side effects in that evaluation will occur irrespective of which (if any) +communication operation is selected to proceed. +Expressions on the left-hand side of a RecvStmt with a short variable declaration +or assignment are not yet evaluated. +
  2. + +
  3. +If one or more of the communications can proceed, +a single one that can proceed is chosen via a uniform pseudo-random selection. +Otherwise, if there is a default case, that case is chosen. +If there is no default case, the "select" statement blocks until +at least one of the communications can proceed. +
  4. + +
  5. +Unless the selected case is the default case, the respective communication +operation is executed. +
  6. + +
  7. +If the selected case is a RecvStmt with a short variable declaration or +an assignment, the left-hand side expressions are evaluated and the +received value (or values) are assigned. +
  8. + +
  9. +The statement list of the selected case is executed. +
  10. +
+

-If multiple cases can proceed, a uniform pseudo-random choice is made to decide -which single communication will execute. -

-The receive case may declare one or two new variables using a -short variable declaration. +Since communication on nil channels can never proceed, +a select with only nil channels and no default case blocks forever.

-var c, c1, c2, c3 chan int
+var a []int
+var c, c1, c2, c3, c4 chan int
 var i1, i2 int
 select {
 case i1 = <-c1:
@@ -4905,6 +4970,10 @@ case i3, ok := (<-c3):  // same as: i3, ok := <-c3
 	} else {
 		print("c3 is closed\n")
 	}
+case a[f()] = <-c4:
+	// same as:
+	// case t := <-c4
+	//	a[f()] = t
 default:
 	print("no communication\n")
 }
@@ -5002,6 +5071,21 @@ function. A "return" statement that specifies results sets the result parameters
 any deferred functions are executed.
 

+

+Implementation restriction: A compiler may disallow an empty expression list +in a "return" statement if a different entity (constant, type, or variable) +with the same name as a result parameter is in +scope at the place of the return. +

+ +
+func f(n int) (res int, err error) {
+	if _, err := f(n-1); err != nil {
+		return  // invalid return statement: err is shadowed
+	}
+	return
+}
+

Break statements

@@ -5009,7 +5093,8 @@ any deferred functions are executed. A "break" statement terminates execution of the innermost "for", "switch", or -"select" statement. +"select" statement +within the same function.

@@ -5043,6 +5128,7 @@ OuterLoop:
 

A "continue" statement begins the next iteration of the innermost "for" loop at its post statement. +The "for" loop must be within the same function.

@@ -5070,7 +5156,8 @@ RowLoop:
 

Goto statements

-A "goto" statement transfers control to the statement with the corresponding label. +A "goto" statement transfers control to the statement with the corresponding label +within the same function.

@@ -5263,7 +5350,7 @@ At any time the following relationship holds:
 
 

The length of a nil slice, map or channel is 0. -The capacity of a nil slice and channel is 0. +The capacity of a nil slice or channel is 0.

@@ -5271,12 +5358,22 @@ The expression len(s) is constant if s is a string constant. The expressions len(s) and cap(s) are constants if the type of s is an array or pointer to an array and the expression s does not contain -channel receives or +channel receives or (non-constant) function calls; in this case s is not evaluated. Otherwise, invocations of len and cap are not constant and s is evaluated.

+
+const (
+	c1 = imag(2i)                    // imag(2i) = 2.0 is a constant
+	c2 = len([10]float64{2})         // [10]float64{2} contains no function calls
+	c3 = len([10]float64{c1})        // [10]float64{c1} contains no function calls
+	c4 = len([10]float64{imag(2i)})  // imag(2i) is a constant and no function call is issued
+	c5 = len([10]float64{imag(z)})   // invalid: imag(x) is a (non-constant) function call
+)
+var z complex128
+

Allocation

@@ -5327,8 +5424,8 @@ make(T, n, m) slice slice of type T with length n and capacity m make(T) map map of type T make(T, n) map map of type T with initial space for n elements -make(T) channel synchronous channel of type T -make(T, n) channel asynchronous channel of type T, buffer size n +make(T) channel unbuffered channel of type T +make(T, n) channel buffered channel of type T, buffer size n
@@ -5669,7 +5766,7 @@ If the PackageName is omitted, it defaults to the identifier specified in the If an explicit period (.) appears instead of a name, all the package's exported identifiers declared in that package's package block will be declared in the importing source -file's file block and can be accessed without a qualifier. +file's file block and must be accessed without a qualifier.

@@ -5681,7 +5778,7 @@ package and may be relative to a repository of installed packages.

Implementation restriction: A compiler may restrict ImportPaths to non-empty strings using only characters belonging to -Unicode's +Unicode's L, M, N, P, and S general categories (the Graphic characters without spaces) and may also exclude the characters !"#$%&'()*,:;<=>?[\]^`{|} @@ -5693,7 +5790,7 @@ Assume we have compiled a package containing the package clause package math, which exports function Sin, and installed the compiled package in the file identified by "lib/math". -This table illustrates how Sin may be accessed in files +This table illustrates how Sin is accessed in files that import the package after the various types of import declaration.

@@ -5817,62 +5914,126 @@ The same would also be true after var t T
-

Program execution

+

Package initialization

-A package with no imports is initialized by assigning initial values to -all its package-level variables -and then calling any -package-level function with the name and signature of -

-
-func init()
-
-

-defined in its source. -A package-scope or file-scope identifier -with name init may only be -declared to be a function with this signature. -Multiple such functions may be defined, even -within a single source file; they execute -in unspecified order. -

-

-Within a package, package-level variables are initialized, -and constant values are determined, according to -order of reference: if the initializer of A -depends on B, A -will be set after B. -Dependency analysis does not depend on the actual values -of the items being initialized, only on their appearance -in the source. -A -depends on B if the value of A -contains a mention of B, contains a value -whose initializer -mentions B, or mentions a function that -mentions B, recursively. -It is an error if such dependencies form a cycle. -If two items are not interdependent, they will be initialized -in the order they appear in the source, possibly in multiple files, -as presented to the compiler. -Since the dependency analysis is done per package, it can produce -unspecified results if A's initializer calls a function defined -in another package that refers to B. +Within a package, package-level variables are initialized according +to their dependencies: if a variable x depends on +a variable y, x will be initialized after +y. +

+ +

+Dependency analysis does not rely on the actual values of the +variables, only on lexical references to them in the source, +analyzed transitively. For instance, a variable x's +initialization expression +may refer to a function whose body refers to variable y; +if so, x depends on y. +Specifically: +

+ +
    +
  • +A reference to a variable or function is an identifier denoting that +variable or function. +
  • + +
  • +A reference to a method m is a +method value or +method expression of the form +t.m, where the (static) type of t is +not an interface type, and the method m is in the +method set of t. +It is immaterial whether the resulting function value +t.m is invoked. +
  • + +
  • +A variable, function, or method x depends on a variable +y if x's initialization expression or body +(for functions and methods) contains a reference to y +or to a function or method that depends on y. +
  • +
+ +

+Dependency analysis is performed per package; only references referring +to variables, functions, and methods declared in the current package +are considered. +It is an error if variable dependencies form a cycle +(but dependency cycles containing no variables are permitted). +If two variables are independent of each other, +they are initialized in the order they are declared +in the source, possibly in multiple files, as presented to the compiler. +

+ +

+For example, given the declarations +

+ +
+var (
+	a = c + b
+	b = f()
+	c = f()
+	d = 3
+)
+
+func f() int {
+	d++
+	return d
+}
+
+ +

+the initialization order is d, b, c, a. +Since b and c are independent of each other, they are +initialized in declaration order (b before c). +

+ +

+Variables may also be initialized using functions named init +declared in the package block, with no arguments and no result parameters.

+ +
+func init() { … }
+
+

-An init function cannot be referred to from anywhere -in a program. In particular, init cannot be called explicitly, -nor can a pointer to init be assigned to a function variable. +Multiple such functions may be defined, even within a single +source file. The init identifier is not +declared and thus +init functions cannot be referred to from anywhere +in a program.

+

+A package with no imports is initialized by assigning initial values +to all its package-level variables followed by calling all init +functions in the order they appear in the source, possibly in multiple files, +as presented to the compiler. If a package has imports, the imported packages are initialized before initializing the package itself. If multiple packages import -a package P, P will be initialized only once. +a package, the imported package will be initialized only once. +The importing of packages, by construction, guarantees that there +can be no cyclic initialization dependencies.

+

-The importing of packages, by construction, guarantees that there can -be no cyclic dependencies in initialization. +Package initialization—variable initialization and the invocation of +init functions—happens in a single goroutine, +sequentially, one package at a time. +An init function may launch other goroutines, which can run +concurrently with the initialization code. However, initialization +always sequences +the init functions: it will not invoke the next one +until the previous one has returned.

+ + +

Program execution

A complete program is created by linking a single, unimported package called the main package with all the packages it imports, transitively. @@ -5889,22 +6050,10 @@ func main() { … }

Program execution begins by initializing the main package and then invoking the function main. -When the function main returns, the program exits. +When that function invocation returns, the program exits. It does not wait for other (non-main) goroutines to complete.

-

-Package initialization—variable initialization and the invocation of -init functions—happens in a single goroutine, -sequentially, one package at a time. -An init function may launch other goroutines, which can run -concurrently with the initialization code. However, initialization -always sequences -the init functions: it will not start the next -init until -the previous one has returned. -

-

Errors

diff --git a/doc/gopher/README b/doc/gopher/README new file mode 100644 index 000000000..936a24c66 --- /dev/null +++ b/doc/gopher/README @@ -0,0 +1,3 @@ +The Go gopher was designed by Renee French. (http://reneefrench.blogspot.com/) +The design is licensed under the Creative Commons 3.0 Attributions license. +Read this article for more details: http://blog.golang.org/gopher diff --git a/doc/help.html b/doc/help.html index 3de520640..ad92c5695 100644 --- a/doc/help.html +++ b/doc/help.html @@ -39,7 +39,7 @@ Go IRC channel.

@golang at Twitter

The Go project's official Twitter account.

-

Tweeting your about problem with the #golang hashtag usually +

Tweeting about your problem with the #golang hashtag usually generates some helpful responses.

Go User Groups

diff --git a/doc/install-source.html b/doc/install-source.html index b99360c71..6f6a15afd 100644 --- a/doc/install-source.html +++ b/doc/install-source.html @@ -69,8 +69,8 @@ goroutines, such as stacks that grow and shrink on demand.

-The compilers can target the FreeBSD, Linux, NetBSD, OpenBSD, OS X (Darwin), Plan 9, -and Windows operating systems. +The compilers can target the DragonFly BSD, FreeBSD, Linux, NetBSD, OpenBSD, +OS X (Darwin), Plan 9, Solaris and Windows operating systems. The full set of supported combinations is listed in the discussion of environment variables below.

@@ -95,7 +95,7 @@ have an hg command.)

If you do not have a working Mercurial installation, follow the instructions on the -Mercurial downloads page. +Mercurial downloads page.

@@ -176,6 +176,10 @@ architecture, and root directory used during the install.

For more information about ways to control the build, see the discussion of environment variables below. +all.bash (or all.bat) runs important tests for Go, +which can take more time than simply building Go. If you do not want to run +the test suite use make.bash (or make.bat) +instead.

@@ -354,9 +358,9 @@ These default to the values of $GOHOSTOS and

Choices for $GOOS are -darwin (Mac OS X 10.6 and above), freebsd, +darwin (Mac OS X 10.6 and above), dragonfly, freebsd, linux, netbsd, openbsd, -plan9, and windows. +plan9, solaris and windows. Choices for $GOARCH are amd64 (64-bit x86, the most mature port), 386 (32-bit x86), and arm (32-bit ARM). @@ -372,6 +376,12 @@ The valid combinations of $GOOS and $GOARCH are: darwin amd64 +dragonfly 386 + + +dragonfly amd64 + + freebsd 386 @@ -411,6 +421,9 @@ The valid combinations of $GOOS and $GOARCH are: plan9 amd64 +solaris amd64 + + windows 386 @@ -444,7 +457,7 @@ installs all commands there.

  • $GO386 (for 386 only, default is auto-detected -if built natively, 387 if not) +if built on either 386 or amd64, 387 otherwise)

    This controls the code generated by 8g to use either the 387 floating-point unit (set to 387) or SSE2 instructions (set to sse2) for diff --git a/doc/install.html b/doc/install.html index af4c8f3d1..7282ae947 100644 --- a/doc/install.html +++ b/doc/install.html @@ -6,15 +6,15 @@

    Download the Go distribution

    - + Download Go Click here to visit the downloads page

    -Official binary -distributions are available for the FreeBSD, Linux, Mac OS X (Snow Leopard +Official binary +distributions are available for the FreeBSD (release 8 and above), Linux, Mac OS X (Snow Leopard and above), and Windows operating systems and the 32-bit (386) and 64-bit (amd64) x86 processor architectures.

    @@ -39,15 +39,15 @@ proceeding. If your OS or architecture is not on the list, it's possible that - - - + + + - + - +
    Operating systemArchitecturesNotesOperating systemArchitecturesNotes

    FreeBSD 7 or later amd64, 386, arm Debian GNU/kFreeBSD not supported; FreeBSD/ARM needs FreeBSD 10 or later
    FreeBSD 8 or later amd64, 386, arm Debian GNU/kFreeBSD not supported; FreeBSD/ARM needs FreeBSD 10 or later
    Linux 2.6.23 or later with glibc amd64, 386, arm CentOS/RHEL 5.x not supported; no binary distribution for ARM yet
    Mac OS X 10.6 or later amd64, 386 use the gcc that comes with Xcode
    Windows 2000 or later amd64, 386 use mingw gcc; cygwin or msys is not needed
    Windows XP or later amd64, 386 use MinGW gcc. No need for cgywin or msys.

    @@ -70,18 +70,19 @@ first remove the existing version.

    Linux, Mac OS X, and FreeBSD tarballs

    -Download the archive +Download the archive and extract it into /usr/local, creating a Go tree in /usr/local/go. For example:

    -tar -C /usr/local -xzf go1.2.1.linux-amd64.tar.gz
    +tar -C /usr/local -xzf go$VERSION.$OS-$ARCH.tar.gz
     

    -The name of the archive may differ, depending on the version of Go you are -installing and your system's operating system and processor architecture. +Choose the archive file appropriate for your installation. +For instance, if you are installing Go version 1.2.1 for 64-bit x86 on Linux, +the archive you want is called go1.2.1.linux-amd64.tar.gz.

    @@ -126,7 +127,7 @@ location.

    Mac OS X package installer

    -Download the package file, +Download the package file, open it, and follow the prompts to install the Go tools. The package installs the Go distribution to /usr/local/go.

    @@ -149,7 +150,7 @@ MSI installer that configures your installation automatically.

    MSI installer

    -Open the MSI file +Open the MSI file and follow the prompts to install the Go tools. By default, the installer puts the Go distribution in c:\Go.

    @@ -163,7 +164,7 @@ command prompts for the change to take effect.

    Zip archive

    -Download the zip file and extract it into the directory of your choice (we suggest c:\Go). +Download the zip file and extract it into the directory of your choice (we suggest c:\Go).

    @@ -227,7 +228,7 @@ You just need to do a little more setup.

    - + How to Write Go Code Learn how to set up and use the Go tools diff --git a/doc/root.html b/doc/root.html index 48280ac35..43637933a 100644 --- a/doc/root.html +++ b/doc/root.html @@ -140,7 +140,6 @@ window.initFuncs.push(function() { var videos = [ {h: 241, s: "//www.youtube.com/embed/ytEkHepK08c"}, // Tour of Go {h: 241, s: "//www.youtube.com/embed/f6kdp27TYZs"}, // Concurrency Patterns - {h: 233, s: "//player.vimeo.com/video/53221560"}, // Grows with grace {h: 233, s: "//player.vimeo.com/video/69237265"} // Simple environment ]; var v = videos[Math.floor(Math.random()*videos.length)]; diff --git a/include/bio.h b/include/bio.h index 5506c7c32..f61409b8a 100644 --- a/include/bio.h +++ b/include/bio.h @@ -33,8 +33,6 @@ extern "C" { AUTOLIB(bio) #endif -#include /* for O_RDONLY, O_WRONLY */ - typedef struct Biobuf Biobuf; enum @@ -75,7 +73,7 @@ struct Biobuf * next few bytes in little-endian order. */ #define BGETC(bp)\ - ((bp)->icount?(bp)->ebuf[(bp)->icount++]:Bgetc((bp))) + ((bp)->icount?(int)((bp)->ebuf[(bp)->icount++]):Bgetc((bp))) #define BGETLE2(bp)\ ((bp)->icount<=-2?((bp)->icount+=2,((bp)->ebuf[(bp)->icount-2])|((bp)->ebuf[(bp)->icount-1]<<8)):Bgetle2((bp))) #define BGETLE4(bp)\ diff --git a/include/bootexec.h b/include/bootexec.h deleted file mode 100644 index 49721ea33..000000000 --- a/include/bootexec.h +++ /dev/null @@ -1,169 +0,0 @@ -// Inferno libmach/bootexec.h -// http://code.google.com/p/inferno-os/source/browse/utils/libmach/bootexec.h -// -// Copyright © 1994-1999 Lucent Technologies Inc. -// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net). -// Portions Copyright © 1997-1999 Vita Nuova Limited. -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). -// Revisions Copyright © 2000-2004 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. - -struct coffsect -{ - char name[8]; - uint32 phys; - uint32 virt; - uint32 size; - uint32 fptr; - uint32 fptrreloc; - uint32 fptrlineno; - uint32 nrelocnlineno; - uint32 flags; -}; - -/* - * proprietary exec headers, needed to bootstrap various machines - */ -struct mipsexec -{ - short mmagic; /* (0x160) mips magic number */ - short nscns; /* (unused) number of sections */ - int32 timdat; /* (unused) time & date stamp */ - int32 symptr; /* offset to symbol table */ - int32 nsyms; /* size of symbol table */ - short opthdr; /* (0x38) sizeof(optional hdr) */ - short pcszs; /* flags */ - short amagic; /* see above */ - short vstamp; /* version stamp */ - int32 tsize; /* text size in bytes */ - int32 dsize; /* initialized data */ - int32 bsize; /* uninitialized data */ - int32 mentry; /* entry pt. */ - int32 text_start; /* base of text used for this file */ - int32 data_start; /* base of data used for this file */ - int32 bss_start; /* base of bss used for this file */ - int32 gprmask; /* general purpose register mask */ -union{ - int32 cprmask[4]; /* co-processor register masks */ - int32 pcsize; -}; - int32 gp_value; /* the gp value used for this object */ -}; - -struct mips4kexec -{ - struct mipsexec h; - struct coffsect itexts; - struct coffsect idatas; - struct coffsect ibsss; -}; - -struct sparcexec -{ - short sjunk; /* dynamic bit and version number */ - short smagic; /* 0407 */ - uint32 stext; - uint32 sdata; - uint32 sbss; - uint32 ssyms; - uint32 sentry; - uint32 strsize; - uint32 sdrsize; -}; - -struct nextexec -{ -/* UNUSED - struct nexthdr{ - uint32 nmagic; - uint32 ncputype; - uint32 ncpusubtype; - uint32 nfiletype; - uint32 ncmds; - uint32 nsizeofcmds; - uint32 nflags; - }; - - struct nextcmd{ - uint32 cmd; - uint32 cmdsize; - uchar segname[16]; - uint32 vmaddr; - uint32 vmsize; - uint32 fileoff; - uint32 filesize; - uint32 maxprot; - uint32 initprot; - uint32 nsects; - uint32 flags; - }textc; - struct nextsect{ - char sectname[16]; - char segname[16]; - uint32 addr; - uint32 size; - uint32 offset; - uint32 align; - uint32 reloff; - uint32 nreloc; - uint32 flags; - uint32 reserved1; - uint32 reserved2; - }texts; - struct nextcmd datac; - struct nextsect datas; - struct nextsect bsss; - struct nextsym{ - uint32 cmd; - uint32 cmdsize; - uint32 symoff; - uint32 nsyms; - uint32 spoff; - uint32 pcoff; - }symc; -*/ -}; - -struct i386exec -{ -/* UNUSED - struct i386coff{ - uint32 isectmagic; - uint32 itime; - uint32 isyms; - uint32 insyms; - uint32 iflags; - }; - struct i386hdr{ - uint32 imagic; - uint32 itextsize; - uint32 idatasize; - uint32 ibsssize; - uint32 ientry; - uint32 itextstart; - uint32 idatastart; - }; - struct coffsect itexts; - struct coffsect idatas; - struct coffsect ibsss; - struct coffsect icomments; -*/ -}; diff --git a/include/link.h b/include/link.h new file mode 100644 index 000000000..248497888 --- /dev/null +++ b/include/link.h @@ -0,0 +1,616 @@ +// Derived from Inferno utils/6l/l.h and related files. +// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h +// +// 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. + +typedef struct Addr Addr; +typedef struct Prog Prog; +typedef struct LSym LSym; +typedef struct Reloc Reloc; +typedef struct Auto Auto; +typedef struct Hist Hist; +typedef struct Link Link; +typedef struct Plist Plist; +typedef struct LinkArch LinkArch; +typedef struct Library Library; + +typedef struct Pcln Pcln; +typedef struct Pcdata Pcdata; +typedef struct Pciter Pciter; + +// prevent incompatible type signatures between liblink and 8l on Plan 9 +#pragma incomplete struct Node + +struct Addr +{ + vlong offset; + + union + { + char sval[8]; + float64 dval; + Prog* branch; // for 5g, 6g, 8g + } u; + + LSym* sym; + LSym* gotype; + short type; + uint8 index; + int8 scale; + int8 reg; // for 5l + int8 name; // for 5l + int8 class; // for 5l + uint8 etype; // for 5g, 6g, 8g + int32 offset2; // for 5l, 8l + struct Node* node; // for 5g, 6g, 8g + int64 width; // for 5g, 6g, 8g +}; + +struct Reloc +{ + int32 off; + uchar siz; + uchar done; + int32 type; + int64 add; + int64 xadd; + LSym* sym; + LSym* xsym; +}; + +struct Prog +{ + vlong pc; + int32 lineno; + Prog* link; + short as; + uchar reg; // arm only + uchar scond; // arm only + Addr from; + Addr to; + + // for 5g, 6g, 8g internal use + void* opt; + + // for 5l, 6l, 8l internal use + Prog* forwd; + Prog* pcond; + Prog* comefrom; // 6l, 8l + Prog* pcrel; // 5l + int32 spadj; + uchar mark; + uchar back; // 6l, 8l + char ft; /* 6l, 8l oclass cache */ + char tt; // 6l, 8l + uchar optab; // 5l + uchar isize; // 6l, 8l + + char width; /* fake for DATA */ + char mode; /* 16, 32, or 64 in 6l, 8l; internal use in 5g, 6g, 8g */ +}; + +// prevent incompatible type signatures between liblink and 8l on Plan 9 +#pragma incomplete struct Section + +struct LSym +{ + char* name; + char* extname; // name used in external object files + short type; + short version; + uchar dupok; + uchar external; + uchar nosplit; + uchar reachable; + uchar cgoexport; + uchar special; + uchar stkcheck; + uchar hide; + uchar leaf; // arm only + uchar fnptr; // arm only + uchar seenglobl; + uchar onlist; // on the textp or datap lists + int16 symid; // for writing .5/.6/.8 files + int32 dynid; + int32 sig; + int32 plt; + int32 got; + int32 align; // if non-zero, required alignment in bytes + int32 elfsym; + int32 args; // size of stack frame incoming arguments area + int32 locals; // size of stack frame locals area (arm only?) + vlong value; + vlong size; + LSym* hash; // in hash table + LSym* allsym; // in all symbol list + LSym* next; // in text or data list + LSym* sub; // in SSUB list + LSym* outer; // container of sub + LSym* gotype; + LSym* reachparent; + LSym* queue; + char* file; + char* dynimplib; + char* dynimpvers; + struct Section* sect; + + // STEXT + Auto* autom; + Prog* text; + Prog* etext; + Pcln* pcln; + + // SDATA, SBSS + uchar* p; + int32 np; + int32 maxp; + Reloc* r; + int32 nr; + int32 maxr; +}; + +// LSym.type +enum +{ + Sxxx, + + /* order here is order in output file */ + /* readonly, executable */ + STEXT, + SELFRXSECT, + + /* readonly, non-executable */ + STYPE, + SSTRING, + SGOSTRING, + SGOFUNC, + SRODATA, + SFUNCTAB, + STYPELINK, + SSYMTAB, // TODO: move to unmapped section + SPCLNTAB, + SELFROSECT, + + /* writable, non-executable */ + SMACHOPLT, + SELFSECT, + SMACHO, /* Mach-O __nl_symbol_ptr */ + SMACHOGOT, + SNOPTRDATA, + SINITARR, + SDATA, + SWINDOWS, + SBSS, + SNOPTRBSS, + STLSBSS, + + /* not mapped */ + SXREF, + SMACHOSYMSTR, + SMACHOSYMTAB, + SMACHOINDIRECTPLT, + SMACHOINDIRECTGOT, + SFILE, + SFILEPATH, + SCONST, + SDYNIMPORT, + SHOSTOBJ, + + SSUB = 1<<8, /* sub-symbol, linked from parent via ->sub list */ + SMASK = SSUB - 1, + SHIDDEN = 1<<9, // hidden or local symbol +}; + +// Reloc.type +enum +{ + R_ADDR = 1, + R_SIZE, + R_CALL, // relocation for direct PC-relative call + R_CALLARM, // relocation for ARM direct call + R_CALLIND, // marker for indirect call (no actual relocating necessary) + R_CONST, + R_PCREL, + R_TLS, + R_TLS_LE, // TLS local exec offset from TLS segment register + R_TLS_IE, // TLS initial exec offset from TLS base pointer + R_GOTOFF, + R_PLT0, + R_PLT1, + R_PLT2, + R_USEFIELD, +}; + +// Auto.type +enum +{ + A_AUTO = 1, + A_PARAM, +}; + +struct Auto +{ + LSym* asym; + Auto* link; + int32 aoffset; + int16 type; + LSym* gotype; +}; + +enum +{ + LINKHASH = 100003, +}; + +struct Hist +{ + Hist* link; + char* name; + int32 line; + int32 offset; +}; + +struct Plist +{ + LSym* name; + Prog* firstpc; + int recur; + Plist* link; +}; + +struct Library +{ + char *objref; // object where we found the reference + char *srcref; // src file where we found the reference + char *file; // object file + char *pkg; // import path +}; + +struct Pcdata +{ + uchar *p; + int n; + int m; +}; + +struct Pcln +{ + Pcdata pcsp; + Pcdata pcfile; + Pcdata pcline; + Pcdata *pcdata; + int npcdata; + LSym **funcdata; + int64 *funcdataoff; + int nfuncdata; + + LSym **file; + int nfile; + int mfile; + + LSym *lastfile; + int lastindex; +}; + +// Pcdata iterator. +// for(pciterinit(ctxt, &it, &pcd); !it.done; pciternext(&it)) { it.value holds in [it.pc, it.nextpc) } +struct Pciter +{ + Pcdata d; + uchar *p; + uint32 pc; + uint32 nextpc; + uint32 pcscale; + int32 value; + int start; + int done; +}; + +void pciterinit(Link*, Pciter*, Pcdata*); +void pciternext(Pciter*); + +// symbol version, incremented each time a file is loaded. +// version==1 is reserved for savehist. +enum +{ + HistVersion = 1, +}; + +// Link holds the context for writing object code from a compiler +// to be linker input or for reading that input into the linker. +struct Link +{ + int32 thechar; // '5' (arm), '6' (amd64), etc. + char* thestring; // full name of architecture ("arm", "amd64", ..) + int32 goarm; // for arm only, GOARM setting + int headtype; + + LinkArch* arch; + int32 (*ignore)(char*); // do not emit names satisfying this function + int32 debugasm; // -S flag in compiler + int32 debugline; // -L flag in compiler + int32 debughist; // -O flag in linker + int32 debugread; // -W flag in linker + int32 debugvlog; // -v flag in linker + int32 debugstack; // -K flag in linker + int32 debugzerostack; // -Z flag in linker + int32 debugdivmod; // -M flag in 5l + int32 debugfloat; // -F flag in 5l + int32 debugpcln; // -O flag in linker + int32 flag_shared; // -shared flag in linker + int32 iself; + Biobuf* bso; // for -v flag + char* pathname; + int32 windows; + char* trimpath; + char* goroot; + char* goroot_final; + + // hash table of all symbols + LSym* hash[LINKHASH]; + LSym* allsym; + int32 nsymbol; + + // file-line history + Hist* hist; + Hist* ehist; + + // all programs + Plist* plist; + Plist* plast; + + // code generation + LSym* sym_div; + LSym* sym_divu; + LSym* sym_mod; + LSym* sym_modu; + LSym* symmorestack[20]; + LSym* gmsym; + LSym* plan9tos; + Prog* curp; + Prog* printp; + Prog* blitrl; + Prog* elitrl; + int rexflag; + int rep; // for nacl + int repn; // for nacl + int lock; // for nacl + int asmode; + uchar* andptr; + uchar and[100]; + int32 instoffset; + int32 autosize; + int32 armsize; + + // for reading input files (during linker) + vlong pc; + char** libdir; + int32 nlibdir; + int32 maxlibdir; + Library* library; + int libraryp; + int nlibrary; + int tlsoffset; + void (*diag)(char*, ...); + int mode; + Auto* curauto; + Auto* curhist; + LSym* cursym; + int version; + LSym* textp; + LSym* etextp; + int32 histdepth; + int32 nhistfile; + LSym* filesyms; +}; + +// LinkArch is the definition of a single architecture. +struct LinkArch +{ + char* name; // "arm", "amd64", and so on + int thechar; // '5', '6', and so on + + void (*addstacksplit)(Link*, LSym*); + void (*assemble)(Link*, LSym*); + int (*datasize)(Prog*); + void (*follow)(Link*, LSym*); + int (*iscall)(Prog*); + int (*isdata)(Prog*); + Prog* (*prg)(void); + void (*progedit)(Link*, Prog*); + void (*settextflag)(Prog*, int); + int (*symtype)(Addr*); + int (*textflag)(Prog*); + + int minlc; + int ptrsize; + int regsize; + + // TODO: Give these the same values on all systems. + int D_ADDR; + int D_AUTO; + int D_BRANCH; + int D_CONST; + int D_EXTERN; + int D_FCONST; + int D_NONE; + int D_PARAM; + int D_SCONST; + int D_STATIC; + + int ACALL; + int ADATA; + int AEND; + int AFUNCDATA; + int AGLOBL; + int AJMP; + int ANOP; + int APCDATA; + int ARET; + int ATEXT; + int ATYPE; + int AUSEFIELD; +}; + +/* executable header types */ +enum { + Hunknown = 0, + Hdarwin, + Hdragonfly, + Helf, + Hfreebsd, + Hlinux, + Hnacl, + Hnetbsd, + Hopenbsd, + Hplan9, + Hsolaris, + Hwindows, +}; + +enum +{ + LinkAuto = 0, + LinkInternal, + LinkExternal, +}; + +extern uchar fnuxi8[8]; +extern uchar fnuxi4[4]; +extern uchar inuxi1[1]; +extern uchar inuxi2[2]; +extern uchar inuxi4[4]; +extern uchar inuxi8[8]; + +// asm5.c +void span5(Link *ctxt, LSym *s); +int chipfloat5(Link *ctxt, float64 e); +int chipzero5(Link *ctxt, float64 e); + +// asm6.c +void span6(Link *ctxt, LSym *s); + +// asm8.c +void span8(Link *ctxt, LSym *s); + +// data.c +vlong addaddr(Link *ctxt, LSym *s, LSym *t); +vlong addaddrplus(Link *ctxt, LSym *s, LSym *t, vlong add); +vlong addaddrplus4(Link *ctxt, LSym *s, LSym *t, vlong add); +vlong addpcrelplus(Link *ctxt, LSym *s, LSym *t, vlong add); +Reloc* addrel(LSym *s); +vlong addsize(Link *ctxt, LSym *s, LSym *t); +vlong adduint16(Link *ctxt, LSym *s, uint16 v); +vlong adduint32(Link *ctxt, LSym *s, uint32 v); +vlong adduint64(Link *ctxt, LSym *s, uint64 v); +vlong adduint8(Link *ctxt, LSym *s, uint8 v); +vlong adduintxx(Link *ctxt, LSym *s, uint64 v, int wid); +void mangle(char *file); +void savedata(Link *ctxt, LSym *s, Prog *p, char *pn); +vlong setaddr(Link *ctxt, LSym *s, vlong off, LSym *t); +vlong setaddrplus(Link *ctxt, LSym *s, vlong off, LSym *t, vlong add); +vlong setuint16(Link *ctxt, LSym *s, vlong r, uint16 v); +vlong setuint32(Link *ctxt, LSym *s, vlong r, uint32 v); +vlong setuint64(Link *ctxt, LSym *s, vlong r, uint64 v); +vlong setuint8(Link *ctxt, LSym *s, vlong r, uint8 v); +vlong setuintxx(Link *ctxt, LSym *s, vlong off, uint64 v, vlong wid); +void symgrow(Link *ctxt, LSym *s, vlong siz); + +// go.c +void double2ieee(uint64 *ieee, double native); +void* emallocz(long n); +void* erealloc(void *p, long n); +char* estrdup(char *p); +char* expandpkg(char *t0, char *pkg); + +// ld.c +void addhist(Link *ctxt, int32 line, int type); +void addlib(Link *ctxt, char *src, char *obj, char *path); +void addlibpath(Link *ctxt, char *srcref, char *objref, char *file, char *pkg); +void collapsefrog(Link *ctxt, LSym *s); +void copyhistfrog(Link *ctxt, char *buf, int nbuf); +int find1(int32 l, int c); +void linkgetline(Link *ctxt, int32 line, LSym **f, int32 *l); +void histtoauto(Link *ctxt); +void mkfwd(LSym*); +void nuxiinit(void); +void savehist(Link *ctxt, int32 line, int32 off); +Prog* copyp(Link*, Prog*); +Prog* appendp(Link*, Prog*); +vlong atolwhex(char*); + +// list[568].c +void listinit5(void); +void listinit6(void); +void listinit8(void); + +// obj.c +int linklinefmt(Link *ctxt, Fmt *fp); +void linklinehist(Link *ctxt, int lineno, char *f, int offset); +Plist* linknewplist(Link *ctxt); +void linkprfile(Link *ctxt, int32 l); + +// objfile.c +void ldobjfile(Link *ctxt, Biobuf *b, char *pkg, int64 len, char *path); +void writeobj(Link *ctxt, Biobuf *b); + +// pass.c +Prog* brchain(Link *ctxt, Prog *p); +Prog* brloop(Link *ctxt, Prog *p); +void linkpatch(Link *ctxt, LSym *sym); + +// pcln.c +void linkpcln(Link*, LSym*); + +// sym.c +LSym* linklookup(Link *ctxt, char *name, int v); +Link* linknew(LinkArch*); +LSym* linknewsym(Link *ctxt, char *symb, int v); +LSym* linkrlookup(Link *ctxt, char *name, int v); +int linksymfmt(Fmt *f); +int headtype(char*); +char* headstr(int); + +extern char* anames5[]; +extern char* anames6[]; +extern char* anames8[]; + +extern LinkArch link386; +extern LinkArch linkamd64; +extern LinkArch linkamd64p32; +extern LinkArch linkarm; + +#pragma varargck type "A" int +#pragma varargck type "D" Addr* +#pragma varargck type "lD" Addr* +#pragma varargck type "P" Prog* +#pragma varargck type "R" int + +// TODO(ality): remove this workaround. +// It's here because Pconv in liblink/list?.c references %L. +#pragma varargck type "L" int32 diff --git a/include/mach.h b/include/mach.h deleted file mode 100644 index cf7151cfd..000000000 --- a/include/mach.h +++ /dev/null @@ -1,411 +0,0 @@ -// Inferno libmach/a.out.h and libmach/mach.h -// http://code.google.com/p/inferno-os/source/browse/utils/libmach/a.out.h -// http://code.google.com/p/inferno-os/source/browse/utils/libmach/mach.h -// -// Copyright © 1994-1999 Lucent Technologies Inc. -// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net). -// Portions Copyright © 1997-1999 Vita Nuova Limited. -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). -// Revisions Copyright © 2000-2004 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. - -/* - * Architecture-dependent application data - */ - -typedef struct Exec Exec; -struct Exec -{ - int32 magic; /* magic number */ - int32 text; /* size of text segment */ - int32 data; /* size of initialized data */ - int32 bss; /* size of uninitialized data */ - int32 syms; /* size of symbol table */ - int32 entry; /* entry point */ - int32 spsz; /* size of pc/sp offset table */ - int32 pcsz; /* size of pc/line number table */ -}; - -#define HDR_MAGIC 0x00008000 /* header expansion */ - -#define _MAGIC(f, b) ((f)|((((4*(b))+0)*(b))+7)) -#define A_MAGIC _MAGIC(0, 8) /* 68020 */ -#define I_MAGIC _MAGIC(0, 11) /* intel 386 */ -#define J_MAGIC _MAGIC(0, 12) /* intel 960 (retired) */ -#define K_MAGIC _MAGIC(0, 13) /* sparc */ -#define V_MAGIC _MAGIC(0, 16) /* mips 3000 BE */ -#define X_MAGIC _MAGIC(0, 17) /* att dsp 3210 (retired) */ -#define M_MAGIC _MAGIC(0, 18) /* mips 4000 BE */ -#define D_MAGIC _MAGIC(0, 19) /* amd 29000 (retired) */ -#define E_MAGIC _MAGIC(0, 20) /* arm */ -#define Q_MAGIC _MAGIC(0, 21) /* powerpc */ -#define N_MAGIC _MAGIC(0, 22) /* mips 4000 LE */ -#define L_MAGIC _MAGIC(0, 23) /* dec alpha */ -#define P_MAGIC _MAGIC(0, 24) /* mips 3000 LE */ -#define U_MAGIC _MAGIC(0, 25) /* sparc64 */ -#define S_MAGIC _MAGIC(HDR_MAGIC, 26) /* amd64 */ -#define T_MAGIC _MAGIC(HDR_MAGIC, 27) /* powerpc64 */ - -#define MIN_MAGIC 8 -#define MAX_MAGIC 27 /* <= 90 */ - -#define DYN_MAGIC 0x80000000 /* dlm */ - -typedef struct Sym Sym; -struct Sym -{ - vlong value; - uint sig; - char type; - char *name; - vlong gotype; - int sequence; // order in file -}; - - -/* - * Supported architectures: - * mips, - * 68020, - * i386, - * amd64, - * sparc, - * sparc64, - * mips2 (R4000) - * arm - * powerpc, - * powerpc64 - * alpha - */ -enum -{ - MMIPS, /* machine types */ - MSPARC, - M68020, - MI386, - MI960, /* retired */ - M3210, /* retired */ - MMIPS2, - NMIPS2, - M29000, /* retired */ - MARM, - MPOWER, - MALPHA, - NMIPS, - MSPARC64, - MAMD64, - MPOWER64, - /* types of executables */ - FNONE = 0, /* unidentified */ - FMIPS, /* v.out */ - FMIPSB, /* mips bootable */ - FSPARC, /* k.out */ - FSPARCB, /* Sparc bootable */ - F68020, /* 2.out */ - F68020B, /* 68020 bootable */ - FNEXTB, /* Next bootable */ - FI386, /* 8.out */ - FI386B, /* I386 bootable */ - FI960, /* retired */ - FI960B, /* retired */ - F3210, /* retired */ - FMIPS2BE, /* 4.out */ - F29000, /* retired */ - FARM, /* 5.out */ - FARMB, /* ARM bootable */ - FPOWER, /* q.out */ - FPOWERB, /* power pc bootable */ - FMIPS2LE, /* 0.out */ - FALPHA, /* 7.out */ - FALPHAB, /* DEC Alpha bootable */ - FMIPSLE, /* 3k little endian */ - FSPARC64, /* u.out */ - FAMD64, /* 6.out */ - FAMD64B, /* 6.out bootable */ - FPOWER64, /* 9.out */ - FPOWER64B, /* 9.out bootable */ - FWINPE, /* windows PE executable */ - - ANONE = 0, /* dissembler types */ - AMIPS, - AMIPSCO, /* native mips */ - ASPARC, - ASUNSPARC, /* native sun */ - A68020, - AI386, - AI8086, /* oh god */ - AI960, /* retired */ - A29000, /* retired */ - AARM, - APOWER, - AALPHA, - ASPARC64, - AAMD64, - APOWER64, - /* object file types */ - Obj68020 = 0, /* .2 */ - ObjSparc, /* .k */ - ObjMips, /* .v */ - Obj386, /* .8 */ - Obj960, /* retired */ - Obj3210, /* retired */ - ObjMips2, /* .4 */ - Obj29000, /* retired */ - ObjArm, /* .5 */ - ObjPower, /* .q */ - ObjMips2le, /* .0 */ - ObjAlpha, /* .7 */ - ObjSparc64, /* .u */ - ObjAmd64, /* .6 */ - ObjSpim, /* .0 */ - ObjPower64, /* .9 */ - Maxobjtype, - - CNONE = 0, /* symbol table classes */ - CAUTO, - CPARAM, - CSTAB, - CTEXT, - CDATA, - CANY, /* to look for any class */ -}; - -typedef struct Map Map; -typedef struct Symbol Symbol; -typedef struct Reglist Reglist; -typedef struct Mach Mach; -typedef struct Machdata Machdata; -typedef struct Seg Seg; - -typedef int Maprw(Map *m, Seg *s, uvlong addr, void *v, uint n, int isread); - -struct Seg { - char *name; /* the segment name */ - int fd; /* file descriptor */ - int inuse; /* in use - not in use */ - int cache; /* should cache reads? */ - uvlong b; /* base */ - uvlong e; /* end */ - vlong f; /* offset within file */ - Maprw *rw; /* read/write fn for seg */ -}; - -/* - * Structure to map a segment to data - */ -struct Map { - int pid; - int tid; - int nsegs; /* number of segments */ - Seg seg[1]; /* actually n of these */ -}; - -/* - * Internal structure describing a symbol table entry - */ -struct Symbol { - void *handle; /* used internally - owning func */ - struct { - char *name; - vlong value; /* address or stack offset */ - char type; /* as in a.out.h */ - char class; /* as above */ - int index; /* in findlocal, globalsym, textsym */ - }; -}; - -/* - * machine register description - */ -struct Reglist { - char *rname; /* register name */ - short roffs; /* offset in u-block */ - char rflags; /* INTEGER/FLOAT, WRITABLE */ - char rformat; /* print format: 'x', 'X', 'f', '8', '3', 'Y', 'W' */ -}; - -enum { /* bits in rflags field */ - RINT = (0<<0), - RFLT = (1<<0), - RRDONLY = (1<<1), -}; - -/* - * Machine-dependent data is stored in two structures: - * Mach - miscellaneous general parameters - * Machdata - jump vector of service functions used by debuggers - * - * Mach is defined in ?.c and set in executable.c - * - * Machdata is defined in ?db.c - * and set in the debugger startup. - */ -struct Mach{ - char *name; - int mtype; /* machine type code */ - Reglist *reglist; /* register set */ - int32 regsize; /* sizeof registers in bytes */ - int32 fpregsize; /* sizeof fp registers in bytes */ - char *pc; /* pc name */ - char *sp; /* sp name */ - char *link; /* link register name */ - char *sbreg; /* static base register name */ - uvlong sb; /* static base register value */ - int pgsize; /* page size */ - uvlong kbase; /* kernel base address */ - uvlong ktmask; /* ktzero = kbase & ~ktmask */ - uvlong utop; /* user stack top */ - int pcquant; /* quantization of pc */ - int szaddr; /* sizeof(void*) */ - int szreg; /* sizeof(register) */ - int szfloat; /* sizeof(float) */ - int szdouble; /* sizeof(double) */ -}; - -extern Mach *mach; /* Current machine */ - -typedef uvlong (*Rgetter)(Map*, char*); -typedef void (*Tracer)(Map*, uvlong, uvlong, Symbol*); - -struct Machdata { /* Machine-dependent debugger support */ - uchar bpinst[4]; /* break point instr. */ - short bpsize; /* size of break point instr. */ - - ushort (*swab)(ushort); /* ushort to local byte order */ - uint32 (*swal)(uint32); /* uint32 to local byte order */ - uvlong (*swav)(uvlong); /* uvlong to local byte order */ - int (*ctrace)(Map*, uvlong, uvlong, uvlong, Tracer); /* C traceback */ - uvlong (*findframe)(Map*, uvlong, uvlong, uvlong, uvlong);/* frame finder */ - char* (*excep)(Map*, Rgetter); /* last exception */ - uint32 (*bpfix)(uvlong); /* breakpoint fixup */ - int (*sftos)(char*, int, void*); /* single precision float */ - int (*dftos)(char*, int, void*); /* double precision float */ - int (*foll)(Map*, uvlong, Rgetter, uvlong*);/* follow set */ - int (*das)(Map*, uvlong, char, char*, int); /* symbolic disassembly */ - int (*hexinst)(Map*, uvlong, char*, int); /* hex disassembly */ - int (*instsize)(Map*, uvlong); /* instruction size */ -}; - -/* - * Common a.out header describing all architectures - */ -typedef struct Fhdr -{ - char *name; /* identifier of executable */ - uchar type; /* file type - see codes above */ - uchar hdrsz; /* header size */ - uchar _magic; /* _MAGIC() magic */ - uchar spare; - int32 magic; /* magic number */ - uvlong txtaddr; /* text address */ - vlong txtoff; /* start of text in file */ - uvlong dataddr; /* start of data segment */ - vlong datoff; /* offset to data seg in file */ - vlong symoff; /* offset of symbol table in file */ - uvlong entry; /* entry point */ - vlong sppcoff; /* offset of sp-pc table in file */ - vlong lnpcoff; /* offset of line number-pc table in file */ - int32 txtsz; /* text size */ - int32 datsz; /* size of data seg */ - int32 bsssz; /* size of bss */ - int32 symsz; /* size of symbol table */ - int32 sppcsz; /* size of sp-pc table */ - int32 lnpcsz; /* size of line number-pc table */ -} Fhdr; - -extern int asstype; /* dissembler type - machdata.c */ -extern Machdata *machdata; /* jump vector - machdata.c */ - -int beieee80ftos(char*, int, void*); -int beieeesftos(char*, int, void*); -int beieeedftos(char*, int, void*); -ushort beswab(ushort); -uint32 beswal(uint32); -uvlong beswav(uvlong); -uvlong ciscframe(Map*, uvlong, uvlong, uvlong, uvlong); -int cisctrace(Map*, uvlong, uvlong, uvlong, Tracer); -int crackhdr(int fd, Fhdr*); -uvlong file2pc(char*, int32); -int fileelem(Sym**, uchar *, char*, int); -int32 fileline(char*, int, uvlong); -int filesym(int, char*, int); -int findlocal(Symbol*, char*, Symbol*); -int findseg(Map*, char*); -int findsym(uvlong, int, Symbol *); -int fnbound(uvlong, uvlong*); -int fpformat(Map*, Reglist*, char*, int, int); -int get1(Map*, uvlong, uchar*, int); -int get2(Map*, uvlong, ushort*); -int get4(Map*, uvlong, uint32*); -int get8(Map*, uvlong, uvlong*); -int geta(Map*, uvlong, uvlong*); -int getauto(Symbol*, int, int, Symbol*); -Sym* getsym(int); -int globalsym(Symbol *, int); -char* _hexify(char*, uint32, int); -int ieeesftos(char*, int, uint32); -int ieeedftos(char*, int, uint32, uint32); -int isar(Biobuf*); -int leieee80ftos(char*, int, void*); -int leieeesftos(char*, int, void*); -int leieeedftos(char*, int, void*); -ushort leswab(ushort); -uint32 leswal(uint32); -uvlong leswav(uvlong); -uvlong line2addr(int32, uvlong, uvlong); -Map* loadmap(Map*, int, Fhdr*); -int localaddr(Map*, char*, char*, uvlong*, Rgetter); -int localsym(Symbol*, int); -int lookup(char*, char*, Symbol*); -void machbytype(int); -int machbyname(char*); -int nextar(Biobuf*, int, char*); -Map* newmap(Map*, int); -void objtraverse(void(*)(Sym*, void*), void*); -int objtype(Biobuf*, char**); -uvlong pc2sp(uvlong); -int32 pc2line(uvlong); -int put1(Map*, uvlong, uchar*, int); -int put2(Map*, uvlong, ushort); -int put4(Map*, uvlong, uint32); -int put8(Map*, uvlong, uvlong); -int puta(Map*, uvlong, uvlong); -int readar(Biobuf*, int, vlong, int); -int readobj(Biobuf*, int); -uvlong riscframe(Map*, uvlong, uvlong, uvlong, uvlong); -int risctrace(Map*, uvlong, uvlong, uvlong, Tracer); -int setmap(Map*, int, uvlong, uvlong, vlong, char*, Maprw *rw); -Sym* symbase(int32*); -int syminit(int, Fhdr*); -int symoff(char*, int, uvlong, int); -void textseg(uvlong, Fhdr*); -int textsym(Symbol*, int); -void unusemap(Map*, int); - -Map* attachproc(int pid, Fhdr *fp); -int ctlproc(int pid, char *msg); -void detachproc(Map *m); -int procnotes(int pid, char ***pnotes); -char* proctextfile(int pid); -int procthreadpids(int pid, int *tid, int ntid); -char* procstatus(int); - -Maprw fdrw; diff --git a/include/plan9/386/u.h b/include/plan9/386/u.h index 4736b8efb..1c4076b5e 100644 --- a/include/plan9/386/u.h +++ b/include/plan9/386/u.h @@ -13,3 +13,5 @@ typedef uint uint32; typedef vlong int64; typedef uvlong uint64; typedef int intptr; +typedef float float32; +typedef double float64; diff --git a/include/plan9/amd64/u.h b/include/plan9/amd64/u.h index 090b2fa5c..c2d499938 100644 --- a/include/plan9/amd64/u.h +++ b/include/plan9/amd64/u.h @@ -13,3 +13,5 @@ typedef uint uint32; typedef vlong int64; typedef uvlong uint64; typedef vlong intptr; +typedef float float32; +typedef double float64; diff --git a/include/plan9/bio.h b/include/plan9/bio.h new file mode 100644 index 000000000..13d5e0ef2 --- /dev/null +++ b/include/plan9/bio.h @@ -0,0 +1,8 @@ +// Copyright 2013 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 "../bio.h" + +#define fmtcharstod charstod +#define lseek seek diff --git a/include/plan9/errno.h b/include/plan9/errno.h new file mode 100644 index 000000000..1ed572ace --- /dev/null +++ b/include/plan9/errno.h @@ -0,0 +1,7 @@ +// Copyright 2014 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. + +int errno; + +#define ERANGE 1001 diff --git a/include/plan9/fmt.h b/include/plan9/fmt.h new file mode 100644 index 000000000..b4a4fe791 --- /dev/null +++ b/include/plan9/fmt.h @@ -0,0 +1,64 @@ +// Copyright 2014 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 "../fmt.h" + +#pragma varargck argpos fmtprint 2 +#pragma varargck argpos fprint 2 +#pragma varargck argpos print 1 +#pragma varargck argpos runeseprint 3 +#pragma varargck argpos runesmprint 1 +#pragma varargck argpos runesnprint 3 +#pragma varargck argpos runesprint 2 +#pragma varargck argpos seprint 3 +#pragma varargck argpos smprint 1 +#pragma varargck argpos snprint 3 +#pragma varargck argpos sprint 2 + +#pragma varargck type "lld" vlong +#pragma varargck type "llo" vlong +#pragma varargck type "llx" vlong +#pragma varargck type "llb" vlong +#pragma varargck type "lld" uvlong +#pragma varargck type "llo" uvlong +#pragma varargck type "llx" uvlong +#pragma varargck type "llb" uvlong +#pragma varargck type "ld" long +#pragma varargck type "lo" long +#pragma varargck type "lx" long +#pragma varargck type "lb" long +#pragma varargck type "ld" ulong +#pragma varargck type "lo" ulong +#pragma varargck type "lx" ulong +#pragma varargck type "lb" ulong +#pragma varargck type "d" int +#pragma varargck type "o" int +#pragma varargck type "x" int +#pragma varargck type "c" int +#pragma varargck type "C" int +#pragma varargck type "b" int +#pragma varargck type "d" uint +#pragma varargck type "x" uint +#pragma varargck type "c" uint +#pragma varargck type "C" uint +#pragma varargck type "b" uint +#pragma varargck type "f" double +#pragma varargck type "e" double +#pragma varargck type "g" double +#pragma varargck type "s" char* +#pragma varargck type "q" char* +#pragma varargck type "S" Rune* +#pragma varargck type "Q" Rune* +#pragma varargck type "r" void +#pragma varargck type "%" void +#pragma varargck type "n" int* +#pragma varargck type "p" uintptr +#pragma varargck type "p" void* +#pragma varargck flag ',' +#pragma varargck flag ' ' +#pragma varargck flag 'h' +#pragma varargck type "<" void* +#pragma varargck type "[" void* +#pragma varargck type "H" void* +#pragma varargck type "lH" void* diff --git a/include/plan9/libc.h b/include/plan9/libc.h index 798e47095..773edeee3 100644 --- a/include/plan9/libc.h +++ b/include/plan9/libc.h @@ -2,8 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include "/sys/include/libc.h" #include "/sys/include/ctype.h" +#include "fmt.h" +#include "utf.h" +#include "libc_plan9.h" char* getgoos(void); char* getgoarch(void); @@ -26,3 +28,6 @@ void flagprint(int); // The libraries use size_t to avoid -Wconversion warnings from GCC // when calling standard library functions like memcpy. typedef unsigned long size_t; + +// math.h +#define HUGE_VAL 1.79769313486231e+308 diff --git a/include/plan9/link.h b/include/plan9/link.h new file mode 100644 index 000000000..f65971efc --- /dev/null +++ b/include/plan9/link.h @@ -0,0 +1,5 @@ +// Copyright 2013 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 "../link.h" diff --git a/include/plan9/mach.h b/include/plan9/mach.h deleted file mode 100644 index 636f44fe8..000000000 --- a/include/plan9/mach.h +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2012 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 "../mach.h" diff --git a/include/plan9/mklibc.rc b/include/plan9/mklibc.rc new file mode 100755 index 000000000..449e15fdf --- /dev/null +++ b/include/plan9/mklibc.rc @@ -0,0 +1,8 @@ +#!/bin/rc + +pattern='/umuldiv/d + /rune routines/,/^\/\*/d + /print routines/,/^\/\*/d + /error string for/,/^\/\*/d' + +sed -e $pattern /sys/include/libc.h | awk '/^enum/ && !n++, /^};/ {next}1' diff --git a/include/plan9/stdarg.h b/include/plan9/stdarg.h new file mode 100644 index 000000000..b562a3a6e --- /dev/null +++ b/include/plan9/stdarg.h @@ -0,0 +1,3 @@ +// Copyright 2014 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. diff --git a/include/plan9/ureg_amd64.h b/include/plan9/ureg_amd64.h deleted file mode 100644 index 8aaa83f52..000000000 --- a/include/plan9/ureg_amd64.h +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2012 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 "/amd64/include/ureg.h" diff --git a/include/plan9/ureg_arm.h b/include/plan9/ureg_arm.h deleted file mode 100644 index f83c19a2f..000000000 --- a/include/plan9/ureg_arm.h +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2012 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 "/arm/include/ureg.h" diff --git a/include/plan9/ureg_x86.h b/include/plan9/ureg_x86.h deleted file mode 100644 index 7d73a4865..000000000 --- a/include/plan9/ureg_x86.h +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2012 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 "/386/include/ureg.h" diff --git a/include/plan9/utf.h b/include/plan9/utf.h new file mode 100644 index 000000000..03c26d69d --- /dev/null +++ b/include/plan9/utf.h @@ -0,0 +1,5 @@ +// Copyright 2014 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 "../utf.h" diff --git a/include/u.h b/include/u.h index 44bfcd63b..6b2d50cc1 100644 --- a/include/u.h +++ b/include/u.h @@ -188,6 +188,8 @@ typedef u32int uint32; typedef s64int int64; typedef u64int uint64; +typedef float float32; +typedef double float64; #undef _NEEDUCHAR #undef _NEEDUSHORT diff --git a/include/ureg_amd64.h b/include/ureg_amd64.h deleted file mode 100644 index 2c39f17ce..000000000 --- a/include/ureg_amd64.h +++ /dev/null @@ -1,58 +0,0 @@ -// Inferno utils/libmach/ureg6.h -// http://code.google.com/p/inferno-os/source/browse/utils/libmach/ureg6.h -// -// Copyright © 1994-1999 Lucent Technologies Inc. -// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net). -// Portions Copyright © 1997-1999 Vita Nuova Limited. -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). -// Revisions Copyright © 2000-2004 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. - -struct Ureg { - u64int ax; - u64int bx; - u64int cx; - u64int dx; - u64int si; - u64int di; - u64int bp; - u64int r8; - u64int r9; - u64int r10; - u64int r11; - u64int r12; - u64int r13; - u64int r14; - u64int r15; - - u16int ds; - u16int es; - u16int fs; - u16int gs; - - u64int type; - u64int error; /* error code (or zero) */ - u64int ip; /* pc */ - u64int cs; /* old context */ - u64int flags; /* old flags */ - u64int sp; /* sp */ - u64int ss; /* old stack segment */ -}; diff --git a/include/ureg_arm.h b/include/ureg_arm.h deleted file mode 100644 index c740b0302..000000000 --- a/include/ureg_arm.h +++ /dev/null @@ -1,49 +0,0 @@ -// Inferno utils/libmach/ureg5.h -// http://code.google.com/p/inferno-os/source/browse/utils/libmach/ureg5.h -// -// Copyright © 1994-1999 Lucent Technologies Inc. -// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net). -// Portions Copyright © 1997-1999 Vita Nuova Limited. -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). -// Revisions Copyright © 2000-2004 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. - -struct Ureg { - uint r0; - uint r1; - uint r2; - uint r3; - uint r4; - uint r5; - uint r6; - uint r7; - uint r8; - uint r9; - uint r10; - uint r11; - uint r12; - uint r13; - uint r14; - uint link; - uint type; - uint psr; - uint pc; -}; diff --git a/include/ureg_x86.h b/include/ureg_x86.h deleted file mode 100644 index c20fe4e4c..000000000 --- a/include/ureg_x86.h +++ /dev/null @@ -1,53 +0,0 @@ -// Inferno utils/libmach/ureg8.h -// http://code.google.com/p/inferno-os/source/browse/utils/libmach/ureg8.h -// -// Copyright © 1994-1999 Lucent Technologies Inc. -// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net). -// Portions Copyright © 1997-1999 Vita Nuova Limited. -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). -// Revisions Copyright © 2000-2004 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. - -struct Ureg -{ - uint32 di; /* general registers */ - uint32 si; /* ... */ - uint32 bp; /* ... */ - uint32 nsp; - uint32 bx; /* ... */ - uint32 dx; /* ... */ - uint32 cx; /* ... */ - uint32 ax; /* ... */ - uint32 gs; /* data segments */ - uint32 fs; /* ... */ - uint32 es; /* ... */ - uint32 ds; /* ... */ - uint32 trap; /* trap type */ - uint32 ecode; /* error code (or zero) */ - uint32 pc; /* pc */ - uint32 cs; /* old context */ - uint32 flags; /* old flags */ - union { - uint32 usp; - uint32 sp; - }; - uint32 ss; /* old stack segment */ -}; diff --git a/lib/time/update.bash b/lib/time/update.bash index f24ef8204..8e1662afd 100755 --- a/lib/time/update.bash +++ b/lib/time/update.bash @@ -6,11 +6,9 @@ # This script rebuilds the time zone files using files # downloaded from the ICANN/IANA distribution. -# NOTE: As of Oct, 2013, the C files will not build on Macs but will build on Linux. - # Versions to use. -CODE=2013g -DATA=2013g +CODE=2014d +DATA=2014d set -e rm -rf work diff --git a/lib/time/zoneinfo.zip b/lib/time/zoneinfo.zip index c9181153f..e0d3afe07 100644 Binary files a/lib/time/zoneinfo.zip and b/lib/time/zoneinfo.zip differ diff --git a/misc/bash/go b/misc/bash/go index f5d79e41a..50f4f720b 100644 --- a/misc/bash/go +++ b/misc/bash/go @@ -20,10 +20,9 @@ _go() local cmd="${COMP_WORDS[1]}" - local cmds="build clean doc fix fmt get + local cmds="build clean env fix fmt get install list run test tool version vet" - local addhelp="gopath importpath remote - testflag testfunc" + local addhelp="c gopath importpath packages testflag testfunc" local other="help" if [ "$COMP_CWORD" == 1 ]; then @@ -88,9 +87,6 @@ _go() COMPREPLY=(`_go_importpath "$cur"`) fi ;; - 'doc') - COMPREPLY=(`_go_importpath "$cur"`) - ;; 'fix') COMPREPLY=(`_go_importpath "$cur"`) ;; @@ -188,15 +184,9 @@ _go() 'dist') # TODO: Implement something. #_go_tool_dist ;; - 'ebnflint') # TODO: Implement something. - #_go_tool_ebnflint - ;; 'fix') # TODO: Implement something. #_go_tool_fix ;; - 'gotype') # TODO: Implement something. - #_go_tool_gotype - ;; 'nm') # TODO: Implement something. #_go_tool_nm ;; @@ -206,9 +196,6 @@ _go() 'pprof') # TODO: Implement something. #_go_tool_pprof ;; - 'prof') # TODO: Implement something. - #_go_tool_prof - ;; 'vet') # TODO: Implement something. #_go_tool_vet ;; diff --git a/misc/benchcmp b/misc/benchcmp index 3180f57ea..28a37392d 100755 --- a/misc/benchcmp +++ b/misc/benchcmp @@ -1,124 +1,5 @@ -#!/bin/sh -# 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. +#!/bin/bash -case "$1" in --*) - echo 'usage: benchcmp old.txt new.txt' >&2 - echo >&2 - echo 'Each input file should be from:' >&2 - echo ' go test -test.run=NONE -test.bench=. > [old,new].txt' >&2 - echo >&2 - echo 'Benchcmp compares the first and last for each benchmark.' >&2 - echo >&2 - echo 'If -test.benchmem=true is added to the "go test" command' >&2 - echo 'benchcmp will also compare memory allocations.' >&2 - exit 2 -esac - -awk ' -BEGIN { - n = 0 -} - -$1 ~ /Benchmark/ && $4 == "ns/op" { - if(old[$1]) { - if(!saw[$1]++) { - name[n++] = $1 - if(length($1) > len) - len = length($1) - } - new[$1] = $3 - if($6 == "MB/s") - newmb[$1] = $5 - - # allocs/op might be at $8 or $10 depending on if - # SetBytes was used or not. - # B/op might be at $6 or $8, it should be immediately - # followed by allocs/op - if($8 == "allocs/op") { - newbytes[$1] = $5 - newalloc[$1] = $7 - } - if($10 == "allocs/op") { - newbytes[$1] = $7 - newalloc[$1] = $9 - } - } else { - old[$1] = $3 - if($6 == "MB/s") - oldmb[$1] = $5 - if($8 == "allocs/op") { - oldbytes[$1] = $5 - oldalloc[$1] = $7 - } - if($10 == "allocs/op") { - oldbytes[$1] = $7 - oldalloc[$1] = $9 - } - } -} - -END { - if(n == 0) { - print "benchcmp: no repeated benchmarks" >"/dev/stderr" - exit 1 - } - - printf("%-*s %12s %12s %7s\n", len, "benchmark", "old ns/op", "new ns/op", "delta") - - # print ns/op - for(i=0; i&2 +echo ' go get -u code.google.com/p/go.tools/cmd/benchcmp' >&2 +exit 2 diff --git a/misc/cgo/errors/err3.go b/misc/cgo/errors/err3.go new file mode 100644 index 000000000..3680a4a4c --- /dev/null +++ b/misc/cgo/errors/err3.go @@ -0,0 +1,18 @@ +// Copyright 2014 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 + +/* +typedef struct foo foo_t; +typedef struct bar bar_t; + +foo_t *foop; +*/ +import "C" + +func main() { + x := (*C.bar_t)(nil) + C.foop = x // ERROR HERE +} diff --git a/misc/cgo/errors/test.bash b/misc/cgo/errors/test.bash index 697ae2fed..f0f60c844 100755 --- a/misc/cgo/errors/test.bash +++ b/misc/cgo/errors/test.bash @@ -26,6 +26,7 @@ check() { check err1.go check err2.go +check err3.go rm -rf errs _obj exit 0 diff --git a/misc/cgo/nocgo/nocgo.go b/misc/cgo/nocgo/nocgo.go new file mode 100644 index 000000000..00ae5e9c8 --- /dev/null +++ b/misc/cgo/nocgo/nocgo.go @@ -0,0 +1,22 @@ +// Copyright 2014 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. + +// Test that -static works when not using cgo. This test is in +// misc/cgo to take advantage of the testing framework support for +// when -static is expected to work. + +package nocgo + +func NoCgo() int { + c := make(chan int) + + // The test is run with external linking, which means that + // goroutines will be created via the runtime/cgo package. + // Make sure that works. + go func() { + c <- 42 + }() + + return <-c +} diff --git a/misc/cgo/nocgo/nocgo_test.go b/misc/cgo/nocgo/nocgo_test.go new file mode 100644 index 000000000..45d247cf9 --- /dev/null +++ b/misc/cgo/nocgo/nocgo_test.go @@ -0,0 +1,14 @@ +// Copyright 2014 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 nocgo + +import "testing" + +func TestNop(t *testing.T) { + i := NoCgo() + if i != 42 { + t.Errorf("got %d, want %d", i, 42) + } +} diff --git a/misc/cgo/test/backdoor/backdoor.go b/misc/cgo/test/backdoor/backdoor.go index efe4f01f4..7398772bd 100644 --- a/misc/cgo/test/backdoor/backdoor.go +++ b/misc/cgo/test/backdoor/backdoor.go @@ -5,3 +5,4 @@ package backdoor func LockedOSThread() bool // in runtime.c +func Issue7695(x1, x2, x3, x4, x5, x6, x7, x8 uintptr) diff --git a/misc/cgo/test/backdoor/backdoor_gccgo.go b/misc/cgo/test/backdoor/backdoor_gccgo.go new file mode 100644 index 000000000..514f76ec5 --- /dev/null +++ b/misc/cgo/test/backdoor/backdoor_gccgo.go @@ -0,0 +1,11 @@ +// Copyright 2014 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 is the gccgo version of the stub in runtime.c. + +// +build gccgo + +package backdoor + +func Issue7695(x1, x2, x3, x4, x5, x6, x7, x8 uintptr) {} diff --git a/misc/cgo/test/backdoor/runtime.c b/misc/cgo/test/backdoor/runtime.c index 194a9c8e4..7e6b44872 100644 --- a/misc/cgo/test/backdoor/runtime.c +++ b/misc/cgo/test/backdoor/runtime.c @@ -23,3 +23,10 @@ void b = runtime·lockedOSThread(); FLUSH(&b); } + +// This is what a cgo-compiled stub declaration looks like. +void +·Issue7695(struct{void *y[8*sizeof(void*)];}p) +{ + USED(p); +} diff --git a/misc/cgo/test/cgo_linux_test.go b/misc/cgo/test/cgo_linux_test.go index 056d67c96..0a405c7a3 100644 --- a/misc/cgo/test/cgo_linux_test.go +++ b/misc/cgo/test/cgo_linux_test.go @@ -7,3 +7,4 @@ package cgotest import "testing" func TestSetgid(t *testing.T) { testSetgid(t) } +func Test6997(t *testing.T) { test6997(t) } diff --git a/misc/cgo/test/cgo_test.go b/misc/cgo/test/cgo_test.go index b7c6d2876..eb237725a 100644 --- a/misc/cgo/test/cgo_test.go +++ b/misc/cgo/test/cgo_test.go @@ -43,12 +43,15 @@ func TestCflags(t *testing.T) { testCflags(t) } func Test5337(t *testing.T) { test5337(t) } func Test5548(t *testing.T) { test5548(t) } func Test5603(t *testing.T) { test5603(t) } +func Test6833(t *testing.T) { test6833(t) } func Test3250(t *testing.T) { test3250(t) } func TestCallbackStack(t *testing.T) { testCallbackStack(t) } func TestFpVar(t *testing.T) { testFpVar(t) } func Test4339(t *testing.T) { test4339(t) } func Test6390(t *testing.T) { test6390(t) } func Test5986(t *testing.T) { test5986(t) } +func Test7665(t *testing.T) { test7665(t) } func TestNaming(t *testing.T) { testNaming(t) } +func Test7560(t *testing.T) { test7560(t) } func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) } diff --git a/misc/cgo/test/issue6833.go b/misc/cgo/test/issue6833.go new file mode 100644 index 000000000..e12d53422 --- /dev/null +++ b/misc/cgo/test/issue6833.go @@ -0,0 +1,27 @@ +// Copyright 2013 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 cgotest + +/* +extern unsigned long long issue6833Func(unsigned int, unsigned long long); +*/ +import "C" + +import "testing" + +//export GoIssue6833Func +func GoIssue6833Func(aui uint, aui64 uint64) uint64 { + return aui64 + uint64(aui) +} + +func test6833(t *testing.T) { + ui := 7 + ull := uint64(0x4000300020001000) + v := uint64(C.issue6833Func(C.uint(ui), C.ulonglong(ull))) + exp := uint64(ui) + ull + if v != exp { + t.Errorf("issue6833Func() returns %x, expected %x", v, exp) + } +} diff --git a/misc/cgo/test/issue6833_c.c b/misc/cgo/test/issue6833_c.c new file mode 100644 index 000000000..a77b425b5 --- /dev/null +++ b/misc/cgo/test/issue6833_c.c @@ -0,0 +1,10 @@ +// Copyright 2013 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 "_cgo_export.h" + +unsigned long long +issue6833Func(unsigned int aui, unsigned long long aull) { + return GoIssue6833Func(aui, aull); +} diff --git a/misc/cgo/test/issue6997_linux.c b/misc/cgo/test/issue6997_linux.c new file mode 100644 index 000000000..897cdd081 --- /dev/null +++ b/misc/cgo/test/issue6997_linux.c @@ -0,0 +1,26 @@ +// Copyright 2014 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 +#include +#include + +static pthread_t thread; + +static void* threadfunc(void* dummy) { + while(1) { + sleep(1); + } +} + +int StartThread() { + return pthread_create(&thread, NULL, &threadfunc, NULL); +} + +int CancelThread() { + void *r; + pthread_cancel(thread); + pthread_join(thread, &r); + return (r == PTHREAD_CANCELED); +} diff --git a/misc/cgo/test/issue6997_linux.go b/misc/cgo/test/issue6997_linux.go new file mode 100644 index 000000000..871bd517a --- /dev/null +++ b/misc/cgo/test/issue6997_linux.go @@ -0,0 +1,40 @@ +// Copyright 2014 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. + +// Test that pthread_cancel works as expected +// (NPTL uses SIGRTMIN to implement thread cancellation) +// See http://golang.org/issue/6997 +package cgotest + +/* +#cgo CFLAGS: -pthread +#cgo LDFLAGS: -pthread +extern int StartThread(); +extern int CancelThread(); +*/ +import "C" + +import "testing" +import "time" + +func test6997(t *testing.T) { + r := C.StartThread() + if r != 0 { + t.Error("pthread_create failed") + } + c := make(chan C.int) + go func() { + time.Sleep(500 * time.Millisecond) + c <- C.CancelThread() + }() + + select { + case r = <-c: + if r == 0 { + t.Error("pthread finished but wasn't cancelled??") + } + case <-time.After(5 * time.Second): + t.Error("hung in pthread_cancel/pthread_join") + } +} diff --git a/misc/cgo/test/issue7234_test.go b/misc/cgo/test/issue7234_test.go new file mode 100644 index 000000000..713dade4c --- /dev/null +++ b/misc/cgo/test/issue7234_test.go @@ -0,0 +1,21 @@ +// Copyright 2014 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 cgotest + +import "testing" + +// This test actually doesn't have anything to do with cgo. It is a +// test of http://golang.org/issue/7234, a compiler/linker bug in +// handling string constants when using -linkmode=external. The test +// is in this directory because we routinely test -linkmode=external +// here. + +var v7234 = [...]string{"runtime/cgo"} + +func TestIssue7234(t *testing.T) { + if v7234[0] != "runtime/cgo" { + t.Errorf("bad string constant %q", v7234[0]) + } +} diff --git a/misc/cgo/test/issue7560.go b/misc/cgo/test/issue7560.go new file mode 100644 index 000000000..4bea6e357 --- /dev/null +++ b/misc/cgo/test/issue7560.go @@ -0,0 +1,44 @@ +// Copyright 2014 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 cgotest + +/* +#include + +typedef struct { + char x; + long y; +} __attribute__((__packed__)) misaligned; + +int +offset7560(void) +{ + return (uintptr_t)&((misaligned*)0)->y; +} +*/ +import "C" + +import ( + "reflect" + "testing" +) + +func test7560(t *testing.T) { + // some mingw don't implement __packed__ correctly. + if C.offset7560() != 1 { + t.Skip("C compiler did not pack struct") + } + + // C.misaligned should have x but then a padding field to get to the end of the struct. + // There should not be a field named 'y'. + var v C.misaligned + rt := reflect.TypeOf(&v).Elem() + if rt.NumField() != 2 || rt.Field(0).Name != "x" || rt.Field(1).Name != "_" { + t.Errorf("unexpected fields in C.misaligned:\n") + for i := 0; i < rt.NumField(); i++ { + t.Logf("%+v\n", rt.Field(i)) + } + } +} diff --git a/misc/cgo/test/issue7665.go b/misc/cgo/test/issue7665.go new file mode 100644 index 000000000..4f36dce75 --- /dev/null +++ b/misc/cgo/test/issue7665.go @@ -0,0 +1,25 @@ +// Copyright 2013 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 cgotest + +import ( + "testing" + "unsafe" +) + +// extern void f7665(void); +import "C" + +//export f7665 +func f7665() {} + +var bad7665 unsafe.Pointer = C.f7665 +var good7665 uintptr = uintptr(C.f7665) + +func test7665(t *testing.T) { + if bad7665 == nil || bad7665 != unsafe.Pointer(good7665) { + t.Errorf("ptrs = %p, %#x, want same non-nil pointer", bad7665, good7665) + } +} diff --git a/misc/cgo/test/issue7695_test.go b/misc/cgo/test/issue7695_test.go new file mode 100644 index 000000000..4bd6f8e73 --- /dev/null +++ b/misc/cgo/test/issue7695_test.go @@ -0,0 +1,27 @@ +// Copyright 2014 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. + +// Demo of deferred C function with untrue prototype +// breaking stack copying. See golang.org/issue/7695. + +package cgotest + +import ( + "testing" + + "./backdoor" +) + +func TestIssue7695(t *testing.T) { + defer backdoor.Issue7695(1, 0, 2, 0, 0, 3, 0, 4) + recurse(100) +} + +func recurse(n int) { + var x [128]int + n += x[0] + if n > 0 { + recurse(n - 1) + } +} diff --git a/misc/cgo/test/issue7786.go b/misc/cgo/test/issue7786.go new file mode 100644 index 000000000..b92763789 --- /dev/null +++ b/misc/cgo/test/issue7786.go @@ -0,0 +1,51 @@ +// Copyright 2013 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. + +// Issue 7786. No runtime test, just make sure that typedef and struct/union/class are interchangeable at compile time. + +package cgotest + +// struct test7786; +// typedef struct test7786 typedef_test7786; +// void f7786(struct test7786 *ctx) {} +// void g7786(typedef_test7786 *ctx) {} +// +// typedef struct body7786 typedef_body7786; +// struct body7786 { int x; }; +// void b7786(struct body7786 *ctx) {} +// void c7786(typedef_body7786 *ctx) {} +// +// typedef union union7786 typedef_union7786; +// void u7786(union union7786 *ctx) {} +// void v7786(typedef_union7786 *ctx) {} +import "C" + +func f() { + var x1 *C.typedef_test7786 + var x2 *C.struct_test7786 + x1 = x2 + x2 = x1 + C.f7786(x1) + C.f7786(x2) + C.g7786(x1) + C.g7786(x2) + + var b1 *C.typedef_body7786 + var b2 *C.struct_body7786 + b1 = b2 + b2 = b1 + C.b7786(b1) + C.b7786(b2) + C.c7786(b1) + C.c7786(b2) + + var u1 *C.typedef_union7786 + var u2 *C.union_union7786 + u1 = u2 + u2 = u1 + C.u7786(u1) + C.u7786(u2) + C.v7786(u1) + C.v7786(u2) +} diff --git a/misc/cgo/test/issue8148.go b/misc/cgo/test/issue8148.go new file mode 100644 index 000000000..8e4190848 --- /dev/null +++ b/misc/cgo/test/issue8148.go @@ -0,0 +1,31 @@ +// Copyright 2014 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. + +// Issue 8148. A typedef of an unnamed struct didn't work when used +// with an exported Go function. No runtime test; just make sure it +// compiles. + +package cgotest + +/* +typedef struct { int i; } T; + +int issue8148Callback(T*); + +static int get() { + T t; + t.i = 42; + return issue8148Callback(&t); +} +*/ +import "C" + +//export issue8148Callback +func issue8148Callback(t *C.T) C.int { + return t.i +} + +func Issue8148() int { + return int(C.get()) +} diff --git a/misc/cgo/test/issue8331.h b/misc/cgo/test/issue8331.h new file mode 100644 index 000000000..936ae9d5c --- /dev/null +++ b/misc/cgo/test/issue8331.h @@ -0,0 +1,7 @@ +// Copyright 2014 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. + +typedef struct { + int i; +} issue8331; diff --git a/misc/cgo/test/issue8331a.go b/misc/cgo/test/issue8331a.go new file mode 100644 index 000000000..7fa55be43 --- /dev/null +++ b/misc/cgo/test/issue8331a.go @@ -0,0 +1,15 @@ +// Copyright 2014 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. + +// Issue 8331. A typedef of an unnamed struct is the same struct when +// #include'd twice. No runtime test; just make sure it compiles. + +package cgotest + +// #include "issue8331.h" +import "C" + +func issue8331a() C.issue8331 { + return issue8331Var +} diff --git a/misc/cgo/test/issue8331b.go b/misc/cgo/test/issue8331b.go new file mode 100644 index 000000000..d52aed63e --- /dev/null +++ b/misc/cgo/test/issue8331b.go @@ -0,0 +1,13 @@ +// Copyright 2014 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. + +// Issue 8331. A typedef of an unnamed struct is the same struct when +// #include'd twice. No runtime test; just make sure it compiles. + +package cgotest + +// #include "issue8331.h" +import "C" + +var issue8331Var C.issue8331 diff --git a/misc/cgo/testcdefs/test.bash b/misc/cgo/testcdefs/test.bash index 1a14ad35c..01621a49a 100755 --- a/misc/cgo/testcdefs/test.bash +++ b/misc/cgo/testcdefs/test.bash @@ -12,5 +12,5 @@ done go build . && ./testcdefs EXIT=$? -rm -rf _obj main *.h +rm -rf _obj testcdefs *.h exit $EXIT diff --git a/misc/cgo/testso/cgoso_c.c b/misc/cgo/testso/cgoso_c.c index 27155c27f..7a38022b5 100644 --- a/misc/cgo/testso/cgoso_c.c +++ b/misc/cgo/testso/cgoso_c.c @@ -19,6 +19,11 @@ extern void goCallback(void); void setCallback(void *f) { (void)f; } #endif +// OpenBSD and older Darwin lack TLS support +#if !defined(__OpenBSD__) && !defined(__APPLE__) +__thread int tlsvar = 12345; +#endif + void sofunc(void) { goCallback(); diff --git a/misc/cgo/testso/cgoso_unix.go b/misc/cgo/testso/cgoso_unix.go new file mode 100644 index 000000000..7d5444cd1 --- /dev/null +++ b/misc/cgo/testso/cgoso_unix.go @@ -0,0 +1,20 @@ +// Copyright 2014 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. + +// +build dragonfly freebsd linux netbsd + +package cgosotest + +/* +extern int __thread tlsvar; +int *getTLS() { return &tlsvar; } +*/ +import "C" + +func init() { + if v := *C.getTLS(); v != 12345 { + println("got", v) + panic("BAD TLS value") + } +} diff --git a/misc/cgo/testtls/tls.go b/misc/cgo/testtls/tls.go index a9546a61c..8e9ee7003 100644 --- a/misc/cgo/testtls/tls.go +++ b/misc/cgo/testtls/tls.go @@ -15,14 +15,16 @@ import ( ) func testTLS(t *testing.T) { - var keyVal C.int = 1234 - runtime.LockOSThread() defer runtime.UnlockOSThread() - C.setTLS(C.int(keyVal)) - storedVal := C.getTLS() - if storedVal != keyVal { - t.Fatalf("stored %d want %d", storedVal, keyVal) + if val := C.getTLS(); val != 0 { + t.Fatalf("at start, C.getTLS() = %#x, want 0", val) + } + + const keyVal = 0x1234 + C.setTLS(keyVal) + if val := C.getTLS(); val != keyVal { + t.Fatalf("at end, C.getTLS() = %#x, want %#x", val, keyVal) } } diff --git a/misc/dist/bindist.go b/misc/dist/bindist.go deleted file mode 100644 index 223d2dc17..000000000 --- a/misc/dist/bindist.go +++ /dev/null @@ -1,1041 +0,0 @@ -// Copyright 2012 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 is a tool for packaging binary releases. -// It supports FreeBSD, Linux, NetBSD, OpenBSD, OS X, and Windows. -package main - -import ( - "archive/tar" - "archive/zip" - "bufio" - "bytes" - "compress/gzip" - "encoding/base64" - "flag" - "fmt" - "io" - "io/ioutil" - "log" - "mime/multipart" - "net/http" - "os" - "os/exec" - "path" - "path/filepath" - "regexp" - "runtime" - "strings" -) - -var ( - tag = flag.String("tag", "release", "mercurial tag to check out") - toolTag = flag.String("tool", defaultToolTag, "go.tools tag to check out") - repo = flag.String("repo", "https://code.google.com/p/go", "repo URL") - verbose = flag.Bool("v", false, "verbose output") - upload = flag.Bool("upload", true, "upload resulting files to Google Code") - wxsFile = flag.String("wxs", "", "path to custom installer.wxs") - addLabel = flag.String("label", "", "additional label to apply to file when uploading") - includeRace = flag.Bool("race", true, "build race detector packages") - versionOverride = flag.String("version", "", "override version name") - staticToolchain = flag.Bool("static", true, "try to build statically linked toolchain (only supported on ELF targets)") - - username, password string // for Google Code upload -) - -const ( - uploadURL = "https://go.googlecode.com/files" - blogPath = "code.google.com/p/go.blog" - toolPath = "code.google.com/p/go.tools" - tourPath = "code.google.com/p/go-tour" - defaultToolTag = "release-branch.go1.2" -) - -// Import paths for tool commands. -// These must be the command that cmd/go knows to install to $GOROOT/bin -// or $GOROOT/pkg/tool. -var toolPaths = []string{ - "code.google.com/p/go.tools/cmd/cover", - "code.google.com/p/go.tools/cmd/godoc", - "code.google.com/p/go.tools/cmd/vet", -} - -var preBuildCleanFiles = []string{ - "lib/codereview", - "misc/dashboard/godashboard", - "src/cmd/cov", - "src/cmd/prof", - "src/pkg/exp", - "src/pkg/old", -} - -var cleanFiles = []string{ - ".hg", - ".hgtags", - ".hgignore", - "VERSION.cache", -} - -var sourceCleanFiles = []string{ - "bin", - "pkg", -} - -var tourPackages = []string{ - "pic", - "tree", - "wc", -} - -var tourContent = []string{ - "content", - "js", - "solutions", - "static", - "template", -} - -var blogContent = []string{ - "content", - "template", -} - -// The os-arches that support the race toolchain. -var raceAvailable = []string{ - "darwin-amd64", - "linux-amd64", - "windows-amd64", -} - -// The OSes that support building statically linked toolchain -// Only ELF platforms are supported. -var staticLinkAvailable = []string{ - "linux", - "freebsd", - "openbsd", - "netbsd", -} - -var fileRe = regexp.MustCompile( - `^(go[a-z0-9-.]+)\.(src|([a-z0-9]+)-([a-z0-9]+)(?:-([a-z0-9.]))?)\.`) - -func main() { - flag.Usage = func() { - fmt.Fprintf(os.Stderr, "usage: %s [flags] targets...\n", os.Args[0]) - flag.PrintDefaults() - os.Exit(2) - } - flag.Parse() - if flag.NArg() == 0 { - flag.Usage() - } - if runtime.GOOS == "windows" { - checkWindowsDeps() - } - - if *upload { - if err := readCredentials(); err != nil { - log.Println("readCredentials:", err) - } - } - for _, targ := range flag.Args() { - var b Build - if m := fileRe.FindStringSubmatch(targ); m != nil { - // targ is a file name; upload it to googlecode. - version := m[1] - if m[2] == "src" { - b.Source = true - } else { - b.OS = m[3] - b.Arch = m[4] - b.Label = m[5] - } - if !*upload { - log.Printf("%s: -upload=false, skipping", targ) - continue - } - if err := b.Upload(version, targ); err != nil { - log.Printf("%s: %v", targ, err) - } - continue - } - if targ == "source" { - b.Source = true - } else { - p := strings.SplitN(targ, "-", 3) - if len(p) < 2 { - log.Println("Ignoring unrecognized target:", targ) - continue - } - b.OS = p[0] - b.Arch = p[1] - if len(p) >= 3 { - b.Label = p[2] - } - if *includeRace { - for _, t := range raceAvailable { - if t == targ || strings.HasPrefix(targ, t+"-") { - b.Race = true - } - } - } - if *staticToolchain { - for _, os := range staticLinkAvailable { - if b.OS == os { - b.static = true - } - } - } - } - if err := b.Do(); err != nil { - log.Printf("%s: %v", targ, err) - } - } -} - -type Build struct { - Source bool // if true, OS and Arch must be empty - Race bool // build race toolchain - OS string - Arch string - Label string - root string - gopath string - static bool // if true, build statically linked toolchain -} - -func (b *Build) Do() error { - work, err := ioutil.TempDir("", "bindist") - if err != nil { - return err - } - defer os.RemoveAll(work) - b.root = filepath.Join(work, "go") - b.gopath = work - - // Clone Go distribution and update to tag. - _, err = b.hgCmd(work, "clone", *repo, b.root) - if err != nil { - return err - } - _, err = b.hgCmd(b.root, "update", *tag) - if err != nil { - return err - } - - // Remove exp and old packages. - if err := b.clean(preBuildCleanFiles); err != nil { - return err - } - - src := filepath.Join(b.root, "src") - if b.Source { - if runtime.GOOS == "windows" { - log.Print("Warning: running make.bash on Windows; source builds are intended to be run on a Unix machine") - } - // Build dist tool only. - _, err = b.run(src, "bash", "make.bash", "--dist-tool") - } else { - // Build. - if b.OS == "windows" { - _, err = b.run(src, "cmd", "/C", "make.bat") - } else { - _, err = b.run(src, "bash", "make.bash") - } - if b.Race { - if err != nil { - return err - } - goCmd := filepath.Join(b.root, "bin", "go") - if b.OS == "windows" { - goCmd += ".exe" - } - _, err = b.run(src, goCmd, "install", "-race", "std") - if err != nil { - return err - } - // Re-install std without -race, so that we're not left - // with a slower, race-enabled cmd/go, etc. - _, err = b.run(src, goCmd, "install", "-a", "std") - // Re-building go command leaves old versions of go.exe as go.exe~ on windows. - // See (*builder).copyFile in $GOROOT/src/cmd/go/build.go for details. - // Remove it manually. - if b.OS == "windows" { - os.Remove(goCmd + "~") - } - } - if err != nil { - return err - } - err = b.tools() - if err != nil { - return err - } - err = b.blog() - if err != nil { - return err - } - err = b.tour() - } - if err != nil { - return err - } - - // Get version strings. - var ( - version string // "weekly.2012-03-04" - fullVersion []byte // "weekly.2012-03-04 9353aa1efdf3" - ) - pat := filepath.Join(b.root, "pkg/tool/*/dist*") // trailing * for .exe - m, err := filepath.Glob(pat) - if err != nil { - return err - } - if len(m) == 0 { - return fmt.Errorf("couldn't find dist in %q", pat) - } - fullVersion, err = b.run("", m[0], "version") - if err != nil { - return err - } - fullVersion = bytes.TrimSpace(fullVersion) - v := bytes.SplitN(fullVersion, []byte(" "), 2) - version = string(v[0]) - if *versionOverride != "" { - version = *versionOverride - } - - // Write VERSION file. - err = ioutil.WriteFile(filepath.Join(b.root, "VERSION"), fullVersion, 0644) - if err != nil { - return err - } - - // Clean goroot. - if err := b.clean(cleanFiles); err != nil { - return err - } - if b.Source { - if err := b.clean(sourceCleanFiles); err != nil { - return err - } - } - - // Create packages. - base := fmt.Sprintf("%s.%s-%s", version, b.OS, b.Arch) - if b.Label != "" { - base += "-" + b.Label - } - if !strings.HasPrefix(base, "go") { - base = "go." + base - } - var targs []string - switch b.OS { - case "linux", "freebsd", "netbsd", "": - // build tarball - targ := base - if b.Source { - targ = fmt.Sprintf("%s.src", version) - if !strings.HasPrefix(targ, "go") { - targ = "go." + targ - } - } - targ += ".tar.gz" - err = makeTar(targ, work) - targs = append(targs, targ) - case "darwin": - // build tarball - targ := base + ".tar.gz" - err = makeTar(targ, work) - targs = append(targs, targ) - - // build pkg - // arrange work so it's laid out as the dest filesystem - etc := filepath.Join(b.root, "misc/dist/darwin/etc") - _, err = b.run(work, "cp", "-r", etc, ".") - if err != nil { - return err - } - localDir := filepath.Join(work, "usr/local") - err = os.MkdirAll(localDir, 0755) - if err != nil { - return err - } - _, err = b.run(work, "mv", "go", localDir) - if err != nil { - return err - } - // build package - pkgdest, err := ioutil.TempDir("", "pkgdest") - if err != nil { - return err - } - defer os.RemoveAll(pkgdest) - dist := filepath.Join(runtime.GOROOT(), "misc/dist") - _, err = b.run("", "pkgbuild", - "--identifier", "com.googlecode.go", - "--version", version, - "--scripts", filepath.Join(dist, "darwin/scripts"), - "--root", work, - filepath.Join(pkgdest, "com.googlecode.go.pkg")) - if err != nil { - return err - } - targ = base + ".pkg" - _, err = b.run("", "productbuild", - "--distribution", filepath.Join(dist, "darwin/Distribution"), - "--resources", filepath.Join(dist, "darwin/Resources"), - "--package-path", pkgdest, - targ) - if err != nil { - return err - } - targs = append(targs, targ) - case "windows": - // Create ZIP file. - zip := filepath.Join(work, base+".zip") - err = makeZip(zip, work) - // Copy zip to target file. - targ := base + ".zip" - err = cp(targ, zip) - if err != nil { - return err - } - targs = append(targs, targ) - - // Create MSI installer. - win := filepath.Join(b.root, "misc/dist/windows") - installer := filepath.Join(win, "installer.wxs") - if *wxsFile != "" { - installer = *wxsFile - } - appfiles := filepath.Join(work, "AppFiles.wxs") - msi := filepath.Join(work, "installer.msi") - // Gather files. - _, err = b.run(work, "heat", "dir", "go", - "-nologo", - "-gg", "-g1", "-srd", "-sfrag", - "-cg", "AppFiles", - "-template", "fragment", - "-dr", "INSTALLDIR", - "-var", "var.SourceDir", - "-out", appfiles) - if err != nil { - return err - } - // Build package. - _, err = b.run(work, "candle", - "-nologo", - "-dVersion="+version, - "-dArch="+b.Arch, - "-dSourceDir=go", - installer, appfiles) - if err != nil { - return err - } - appfiles = filepath.Join(work, "AppFiles.wixobj") - installer = filepath.Join(work, "installer.wixobj") - _, err = b.run(win, "light", - "-nologo", - "-ext", "WixUIExtension", - "-ext", "WixUtilExtension", - installer, appfiles, - "-o", msi) - if err != nil { - return err - } - // Copy installer to target file. - targ = base + ".msi" - err = cp(targ, msi) - targs = append(targs, targ) - } - if err == nil && *upload { - for _, targ := range targs { - err = b.Upload(version, targ) - if err != nil { - return err - } - } - } - return err -} - -func (b *Build) tools() error { - defer b.cleanGopath() - - // Fetch the tool packages (without building/installing). - args := append([]string{"get", "-d"}, toolPaths...) - _, err := b.run(b.gopath, filepath.Join(b.root, "bin", "go"), args...) - if err != nil { - return err - } - - // Update the repo to the revision specified by -tool. - repoPath := filepath.Join(b.gopath, "src", filepath.FromSlash(toolPath)) - _, err = b.run(repoPath, "hg", "update", *toolTag) - if err != nil { - return err - } - - // Install tools. - args = append([]string{"install"}, toolPaths...) - _, err = b.run(b.gopath, filepath.Join(b.root, "bin", "go"), args...) - if err != nil { - return err - } - - // Copy doc.go from go.tools/cmd/$CMD to $GOROOT/src/cmd/$CMD - // while rewriting "package main" to "package documentation". - for _, p := range toolPaths { - d, err := ioutil.ReadFile(filepath.Join(b.gopath, "src", - filepath.FromSlash(p), "doc.go")) - if err != nil { - return err - } - d = bytes.Replace(d, []byte("\npackage main\n"), - []byte("\npackage documentation\n"), 1) - cmdDir := filepath.Join(b.root, "src", "cmd", path.Base(p)) - if err := os.MkdirAll(cmdDir, 0755); err != nil { - return err - } - docGo := filepath.Join(cmdDir, "doc.go") - if err := ioutil.WriteFile(docGo, d, 0644); err != nil { - return err - } - } - - return nil -} - -func (b *Build) blog() error { - defer b.cleanGopath() - - // Fetch the blog repository. - _, err := b.run(b.gopath, filepath.Join(b.root, "bin", "go"), "get", "-d", blogPath+"/blog") - if err != nil { - return err - } - - // Copy blog content to $GOROOT/blog. - blogSrc := filepath.Join(b.gopath, "src", filepath.FromSlash(blogPath)) - contentDir := filepath.Join(b.root, "blog") - return cpAllDir(contentDir, blogSrc, blogContent...) -} - -func (b *Build) tour() error { - defer b.cleanGopath() - - // go get the gotour package. - _, err := b.run(b.gopath, filepath.Join(b.root, "bin", "go"), "get", tourPath+"/gotour") - if err != nil { - return err - } - - // Copy all the tour content to $GOROOT/misc/tour. - importPath := filepath.FromSlash(tourPath) - tourSrc := filepath.Join(b.gopath, "src", importPath) - contentDir := filepath.Join(b.root, "misc", "tour") - if err = cpAllDir(contentDir, tourSrc, tourContent...); err != nil { - return err - } - - // Copy the tour source code so it's accessible with $GOPATH pointing to $GOROOT/misc/tour. - if err = cpAllDir(filepath.Join(contentDir, "src", importPath), tourSrc, tourPackages...); err != nil { - return err - } - - // Copy gotour binary to tool directory as "tour"; invoked as "go tool tour". - return cp( - filepath.Join(b.root, "pkg", "tool", b.OS+"_"+b.Arch, "tour"+ext()), - filepath.Join(b.gopath, "bin", "gotour"+ext()), - ) -} - -func (b *Build) cleanGopath() { - for _, d := range []string{"bin", "pkg", "src"} { - os.RemoveAll(filepath.Join(b.gopath, d)) - } -} - -func ext() string { - if runtime.GOOS == "windows" { - return ".exe" - } - return "" -} - -func (b *Build) hgCmd(dir string, args ...string) ([]byte, error) { - return b.run(dir, "hg", append([]string{"--config", "extensions.codereview=!"}, args...)...) -} - -func (b *Build) run(dir, name string, args ...string) ([]byte, error) { - buf := new(bytes.Buffer) - absName, err := lookPath(name) - if err != nil { - return nil, err - } - cmd := exec.Command(absName, args...) - var output io.Writer = buf - if *verbose { - log.Printf("Running %q %q", absName, args) - output = io.MultiWriter(buf, os.Stdout) - } - cmd.Stdout = output - cmd.Stderr = output - cmd.Dir = dir - cmd.Env = b.env() - if err := cmd.Run(); err != nil { - fmt.Fprintf(os.Stderr, "%s", buf.Bytes()) - return nil, fmt.Errorf("%s %s: %v", name, strings.Join(args, " "), err) - } - return buf.Bytes(), nil -} - -var cleanEnv = []string{ - "GOARCH", - "GOBIN", - "GOHOSTARCH", - "GOHOSTOS", - "GOOS", - "GOROOT", - "GOROOT_FINAL", - "GOPATH", -} - -func (b *Build) env() []string { - env := os.Environ() - for i := 0; i < len(env); i++ { - for _, c := range cleanEnv { - if strings.HasPrefix(env[i], c+"=") { - env = append(env[:i], env[i+1:]...) - } - } - } - final := "/usr/local/go" - if b.OS == "windows" { - final = `c:\go` - } - env = append(env, - "GOARCH="+b.Arch, - "GOHOSTARCH="+b.Arch, - "GOHOSTOS="+b.OS, - "GOOS="+b.OS, - "GOROOT="+b.root, - "GOROOT_FINAL="+final, - "GOPATH="+b.gopath, - ) - if b.static { - env = append(env, "GO_DISTFLAGS=-s") - } - return env -} - -func (b *Build) Upload(version string, filename string) error { - // Prepare upload metadata. - var labels []string - os_, arch := b.OS, b.Arch - switch b.Arch { - case "386": - arch = "x86 32-bit" - case "amd64": - arch = "x86 64-bit" - } - if arch != "" { - labels = append(labels, "Arch-"+b.Arch) - } - var opsys, ftype string // labels - switch b.OS { - case "linux": - os_ = "Linux" - opsys = "Linux" - case "freebsd": - os_ = "FreeBSD" - opsys = "FreeBSD" - case "darwin": - os_ = "Mac OS X" - opsys = "OSX" - case "netbsd": - os_ = "NetBSD" - opsys = "NetBSD" - case "windows": - os_ = "Windows" - opsys = "Windows" - } - summary := fmt.Sprintf("%s %s (%s)", version, os_, arch) - switch { - case strings.HasSuffix(filename, ".msi"): - ftype = "Installer" - summary += " MSI installer" - case strings.HasSuffix(filename, ".pkg"): - ftype = "Installer" - summary += " PKG installer" - case strings.HasSuffix(filename, ".zip"): - ftype = "Archive" - summary += " ZIP archive" - case strings.HasSuffix(filename, ".tar.gz"): - ftype = "Archive" - summary += " tarball" - } - if b.Source { - ftype = "Source" - summary = fmt.Sprintf("%s (source only)", version) - } - if opsys != "" { - labels = append(labels, "OpSys-"+opsys) - } - if ftype != "" { - labels = append(labels, "Type-"+ftype) - } - if b.Label != "" { - labels = append(labels, b.Label) - } - if *addLabel != "" { - labels = append(labels, *addLabel) - } - // Put "Go" prefix on summary when it doesn't already begin with "go". - if !strings.HasPrefix(strings.ToLower(summary), "go") { - summary = "Go " + summary - } - - // Open file to upload. - f, err := os.Open(filename) - if err != nil { - return err - } - defer f.Close() - - // Prepare multipart payload. - body := new(bytes.Buffer) - w := multipart.NewWriter(body) - if err := w.WriteField("summary", summary); err != nil { - return err - } - for _, l := range labels { - if err := w.WriteField("label", l); err != nil { - return err - } - } - fw, err := w.CreateFormFile("filename", filename) - if err != nil { - return err - } - if _, err = io.Copy(fw, f); err != nil { - return err - } - if err := w.Close(); err != nil { - return err - } - - // Send the file to Google Code. - req, err := http.NewRequest("POST", uploadURL, body) - if err != nil { - return err - } - token := fmt.Sprintf("%s:%s", username, password) - token = base64.StdEncoding.EncodeToString([]byte(token)) - req.Header.Set("Authorization", "Basic "+token) - req.Header.Set("Content-type", w.FormDataContentType()) - - resp, err := http.DefaultTransport.RoundTrip(req) - if err != nil { - return err - } - if resp.StatusCode/100 != 2 { - fmt.Fprintln(os.Stderr, "upload failed") - defer resp.Body.Close() - io.Copy(os.Stderr, resp.Body) - return fmt.Errorf("upload: %s", resp.Status) - } - return nil -} - -func (b *Build) clean(files []string) error { - for _, name := range files { - err := os.RemoveAll(filepath.Join(b.root, name)) - if err != nil { - return err - } - } - return nil -} - -func exists(path string) bool { - _, err := os.Stat(path) - return err == nil -} - -func readCredentials() error { - name := os.Getenv("HOME") - if runtime.GOOS == "windows" { - name = os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH") - } - name = filepath.Join(name, ".gobuildkey") - f, err := os.Open(name) - if err != nil { - return err - } - defer f.Close() - r := bufio.NewReader(f) - for i := 0; i < 3; i++ { - b, _, err := r.ReadLine() - if err != nil { - return err - } - b = bytes.TrimSpace(b) - switch i { - case 1: - username = string(b) - case 2: - password = string(b) - } - } - return nil -} - -func cp(dst, src string) error { - sf, err := os.Open(src) - if err != nil { - return err - } - defer sf.Close() - fi, err := sf.Stat() - if err != nil { - return err - } - df, err := os.Create(dst) - if err != nil { - return err - } - defer df.Close() - // Windows doesn't currently implement Fchmod - if runtime.GOOS != "windows" { - if err := df.Chmod(fi.Mode()); err != nil { - return err - } - } - _, err = io.Copy(df, sf) - return err -} - -func cpDir(dst, src string) error { - walk := func(srcPath string, info os.FileInfo, err error) error { - if err != nil { - return err - } - dstPath := filepath.Join(dst, srcPath[len(src):]) - if info.IsDir() { - return os.MkdirAll(dstPath, 0755) - } - return cp(dstPath, srcPath) - } - return filepath.Walk(src, walk) -} - -func cpAllDir(dst, basePath string, dirs ...string) error { - for _, dir := range dirs { - if err := cpDir(filepath.Join(dst, dir), filepath.Join(basePath, dir)); err != nil { - return err - } - } - return nil -} - -func makeTar(targ, workdir string) error { - f, err := os.Create(targ) - if err != nil { - return err - } - zout := gzip.NewWriter(f) - tw := tar.NewWriter(zout) - - err = filepath.Walk(workdir, func(path string, fi os.FileInfo, err error) error { - if !strings.HasPrefix(path, workdir) { - log.Panicf("walked filename %q doesn't begin with workdir %q", path, workdir) - } - name := path[len(workdir):] - - // Chop of any leading / from filename, leftover from removing workdir. - if strings.HasPrefix(name, "/") { - name = name[1:] - } - // Don't include things outside of the go subdirectory (for instance, - // the zip file that we're currently writing here.) - if !strings.HasPrefix(name, "go/") { - return nil - } - if *verbose { - log.Printf("adding to tar: %s", name) - } - target, _ := os.Readlink(path) - hdr, err := tar.FileInfoHeader(fi, target) - if err != nil { - return err - } - hdr.Name = name - hdr.Uname = "root" - hdr.Gname = "root" - hdr.Uid = 0 - hdr.Gid = 0 - - // Force permissions to 0755 for executables, 0644 for everything else. - if fi.Mode().Perm()&0111 != 0 { - hdr.Mode = hdr.Mode&^0777 | 0755 - } else { - hdr.Mode = hdr.Mode&^0777 | 0644 - } - - err = tw.WriteHeader(hdr) - if err != nil { - return fmt.Errorf("Error writing file %q: %v", name, err) - } - if fi.IsDir() { - return nil - } - r, err := os.Open(path) - if err != nil { - return err - } - defer r.Close() - _, err = io.Copy(tw, r) - return err - }) - if err != nil { - return err - } - if err := tw.Close(); err != nil { - return err - } - if err := zout.Close(); err != nil { - return err - } - return f.Close() -} - -func makeZip(targ, workdir string) error { - f, err := os.Create(targ) - if err != nil { - return err - } - zw := zip.NewWriter(f) - - err = filepath.Walk(workdir, func(path string, fi os.FileInfo, err error) error { - if !strings.HasPrefix(path, workdir) { - log.Panicf("walked filename %q doesn't begin with workdir %q", path, workdir) - } - name := path[len(workdir):] - - // Convert to Unix-style named paths, as that's the - // type of zip file that archive/zip creates. - name = strings.Replace(name, "\\", "/", -1) - // Chop of any leading / from filename, leftover from removing workdir. - if strings.HasPrefix(name, "/") { - name = name[1:] - } - // Don't include things outside of the go subdirectory (for instance, - // the zip file that we're currently writing here.) - if !strings.HasPrefix(name, "go/") { - return nil - } - if *verbose { - log.Printf("adding to zip: %s", name) - } - fh, err := zip.FileInfoHeader(fi) - if err != nil { - return err - } - fh.Name = name - fh.Method = zip.Deflate - if fi.IsDir() { - fh.Name += "/" // append trailing slash - fh.Method = zip.Store // no need to deflate 0 byte files - } - w, err := zw.CreateHeader(fh) - if err != nil { - return err - } - if fi.IsDir() { - return nil - } - r, err := os.Open(path) - if err != nil { - return err - } - defer r.Close() - _, err = io.Copy(w, r) - return err - }) - if err != nil { - return err - } - if err := zw.Close(); err != nil { - return err - } - return f.Close() -} - -type tool struct { - name string - commonDirs []string -} - -var wixTool = tool{ - "http://wix.sourceforge.net/, version 3.5", - []string{`C:\Program Files\Windows Installer XML v3.5\bin`, - `C:\Program Files (x86)\Windows Installer XML v3.5\bin`}, -} - -var hgTool = tool{ - "http://mercurial.selenic.com/wiki/WindowsInstall", - []string{`C:\Program Files\Mercurial`, - `C:\Program Files (x86)\Mercurial`, - }, -} - -var gccTool = tool{ - "Mingw gcc; http://sourceforge.net/projects/mingw/files/Installer/mingw-get-inst/", - []string{`C:\Mingw\bin`}, -} - -var windowsDeps = map[string]tool{ - "gcc": gccTool, - "heat": wixTool, - "candle": wixTool, - "light": wixTool, - "cmd": {"Windows cmd.exe", nil}, - "hg": hgTool, -} - -func checkWindowsDeps() { - for prog, help := range windowsDeps { - absPath, err := lookPath(prog) - if err != nil { - log.Fatalf("Failed to find necessary binary %q in path or common locations; %s", prog, help) - } - if *verbose { - log.Printf("found windows dep %s at %s", prog, absPath) - } - } -} - -func lookPath(prog string) (absPath string, err error) { - absPath, err = exec.LookPath(prog) - if err == nil { - return - } - t, ok := windowsDeps[prog] - if !ok { - return - } - for _, dir := range t.commonDirs { - for _, ext := range []string{"exe", "bat"} { - absPath = filepath.Join(dir, prog+"."+ext) - if _, err1 := os.Stat(absPath); err1 == nil { - err = nil - os.Setenv("PATH", os.Getenv("PATH")+";"+dir) - return - } - } - } - return -} diff --git a/misc/dist/darwin/Distribution b/misc/dist/darwin/Distribution deleted file mode 100644 index 8b764b69f..000000000 --- a/misc/dist/darwin/Distribution +++ /dev/null @@ -1,32 +0,0 @@ - - - Go - - - - - - - - - - - - com.googlecode.go.pkg - diff --git a/misc/dist/darwin/Resources/bg.png b/misc/dist/darwin/Resources/bg.png deleted file mode 100644 index c3d8ea93a..000000000 Binary files a/misc/dist/darwin/Resources/bg.png and /dev/null differ diff --git a/misc/dist/darwin/etc/paths.d/go b/misc/dist/darwin/etc/paths.d/go deleted file mode 100644 index 532e5f936..000000000 --- a/misc/dist/darwin/etc/paths.d/go +++ /dev/null @@ -1 +0,0 @@ -/usr/local/go/bin diff --git a/misc/dist/darwin/scripts/postinstall b/misc/dist/darwin/scripts/postinstall deleted file mode 100755 index 13f5bff9b..000000000 --- a/misc/dist/darwin/scripts/postinstall +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -GOROOT=/usr/local/go - -echo "Fixing permissions" -cd $GOROOT -find . -exec chmod ugo+r \{\} \; -find bin -exec chmod ugo+rx \{\} \; -find . -type d -exec chmod ugo+rx \{\} \; -chmod o-w . diff --git a/misc/dist/darwin/scripts/preinstall b/misc/dist/darwin/scripts/preinstall deleted file mode 100755 index 4cdaaa4bc..000000000 --- a/misc/dist/darwin/scripts/preinstall +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -GOROOT=/usr/local/go - -echo "Removing previous installation" -if [ -d $GOROOT ]; then - rm -r $GOROOT -fi diff --git a/misc/dist/windows/LICENSE.rtf b/misc/dist/windows/LICENSE.rtf deleted file mode 100644 index b2b0be62c..000000000 Binary files a/misc/dist/windows/LICENSE.rtf and /dev/null differ diff --git a/misc/dist/windows/README.txt b/misc/dist/windows/README.txt deleted file mode 100644 index 0cf828b24..000000000 --- a/misc/dist/windows/README.txt +++ /dev/null @@ -1,25 +0,0 @@ - -Windows build dependencies - -- Mercurial (hg): http://mercurial.selenic.com/ -- MinGW: http://www.mingw.org/ -- Windows Installer XML (WiX) toolset: http://wix.sourceforge.net/ - -Packaging - -The dependencies must be in/added to the system's search PATH. - -Run bindist as normal, eg: - bindist windows-386 - -TODO - -- Documentation server shortcut checkbox option - -Misc - -WiX box sizes: - - banner size: 493x58 - - left side of dialog: 164x312 - - full dialog size: 493x312 - diff --git a/misc/dist/windows/images/Banner.jpg b/misc/dist/windows/images/Banner.jpg deleted file mode 100644 index ce65f63af..000000000 Binary files a/misc/dist/windows/images/Banner.jpg and /dev/null differ diff --git a/misc/dist/windows/images/Dialog.jpg b/misc/dist/windows/images/Dialog.jpg deleted file mode 100644 index 1f0ec0a31..000000000 Binary files a/misc/dist/windows/images/Dialog.jpg and /dev/null differ diff --git a/misc/dist/windows/images/DialogLeft.jpg b/misc/dist/windows/images/DialogLeft.jpg deleted file mode 100644 index 73bab89b4..000000000 Binary files a/misc/dist/windows/images/DialogLeft.jpg and /dev/null differ diff --git a/misc/dist/windows/images/gopher.ico b/misc/dist/windows/images/gopher.ico deleted file mode 100644 index 2e861ebe0..000000000 Binary files a/misc/dist/windows/images/gopher.ico and /dev/null differ diff --git a/misc/dist/windows/installer.wxs b/misc/dist/windows/installer.wxs deleted file mode 100644 index b170b98dc..000000000 --- a/misc/dist/windows/installer.wxs +++ /dev/null @@ -1,164 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - -1 - - - - VersionNT >= 500 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/misc/emacs/go-mode.el b/misc/emacs/go-mode.el index 75b28ac73..6333ff966 100644 --- a/misc/emacs/go-mode.el +++ b/misc/emacs/go-mode.el @@ -7,6 +7,7 @@ (require 'cl) (require 'etags) (require 'ffap) +(require 'find-file) (require 'ring) (require 'url) @@ -61,6 +62,7 @@ ;; macro. (if nil (declare-function go--position-bytes "go-mode" (point))) + ;; XEmacs unfortunately does not offer position-bytes. We can fall ;; back to just using (point), but it will be incorrect as soon as ;; multibyte characters are being used. @@ -167,6 +169,13 @@ from https://github.com/bradfitz/goimports." :type 'string :group 'go) +(defcustom go-other-file-alist + '(("_test\\.go\\'" (".go")) + ("\\.go\\'" ("_test.go"))) + "See the documentation of `ff-other-file-alist' for details." + :type '(repeat (list regexp (choice (repeat string) function))) + :group 'go) + (defface go-coverage-untracked '((t (:foreground "#505050"))) "Coverage color of untracked code." @@ -249,22 +258,23 @@ For mode=set, all covered lines will have this weight." "Syntax table for Go mode.") (defun go--build-font-lock-keywords () - ;; we cannot use 'symbols in regexp-opt because emacs <24 doesn't - ;; understand that + ;; we cannot use 'symbols in regexp-opt because GNU Emacs <24 + ;; doesn't understand that (append `((,(go--regexp-enclose-in-symbol (regexp-opt go-mode-keywords t)) . font-lock-keyword-face) - (,(go--regexp-enclose-in-symbol (regexp-opt go-builtins t)) . font-lock-builtin-face) + (,(concat "\\(" (go--regexp-enclose-in-symbol (regexp-opt go-builtins t)) "\\)[[:space:]]*(") 1 font-lock-builtin-face) (,(go--regexp-enclose-in-symbol (regexp-opt go-constants t)) . font-lock-constant-face) (,go-func-regexp 1 font-lock-function-name-face)) ;; function (not method) name (if go-fontify-function-calls `((,(concat "\\(" go-identifier-regexp "\\)[[:space:]]*(") 1 font-lock-function-name-face) ;; function call/method name (,(concat "[^[:word:][:multibyte:]](\\(" go-identifier-regexp "\\))[[:space:]]*(") 1 font-lock-function-name-face)) ;; bracketed function call - `((,go-func-meth-regexp 1 font-lock-function-name-face))) ;; method name + `((,go-func-meth-regexp 2 font-lock-function-name-face))) ;; method name `( - (,(concat (go--regexp-enclose-in-symbol "type") "[[:space:]]*\\([^[:space:]]+\\)") 1 font-lock-type-face) ;; types - (,(concat (go--regexp-enclose-in-symbol "type") "[[:space:]]*" go-identifier-regexp "[[:space:]]*" go-type-name-regexp) 1 font-lock-type-face) ;; types + ("\\(`[^`]*`\\)" 1 font-lock-multiline) ;; raw string literal, needed for font-lock-syntactic-keywords + (,(concat (go--regexp-enclose-in-symbol "type") "[[:space:]]+\\([^[:space:]]+\\)") 1 font-lock-type-face) ;; types + (,(concat (go--regexp-enclose-in-symbol "type") "[[:space:]]+" go-identifier-regexp "[[:space:]]*" go-type-name-regexp) 1 font-lock-type-face) ;; types (,(concat "[^[:word:][:multibyte:]]\\[\\([[:digit:]]+\\|\\.\\.\\.\\)?\\]" go-type-name-regexp) 2 font-lock-type-face) ;; Arrays/slices (,(concat "\\(" go-identifier-regexp "\\)" "{") 1 font-lock-type-face) (,(concat (go--regexp-enclose-in-symbol "map") "\\[[^]]+\\]" go-type-name-regexp) 1 font-lock-type-face) ;; map value type @@ -281,6 +291,14 @@ For mode=set, all covered lines will have this weight." (,(concat "^[[:space:]]*\\(" go-label-regexp "\\)[[:space:]]*:\\(\\S.\\|$\\)") 1 font-lock-constant-face) ;; Labels and compound literal fields (,(concat (go--regexp-enclose-in-symbol "\\(goto\\|break\\|continue\\)") "[[:space:]]*\\(" go-label-regexp "\\)") 2 font-lock-constant-face)))) ;; labels in goto/break/continue +(defconst go--font-lock-syntactic-keywords + ;; Override syntax property of raw string literal contents, so that + ;; backslashes have no special meaning in ``. Used in Emacs 23 or older. + '((go--match-raw-string-literal + (1 (7 . ?`)) + (2 (15 . nil)) ;; 15 = "generic string" + (3 (7 . ?`))))) + (defvar go-mode-map (let ((m (make-sparse-keymap))) (define-key m "}" #'go-mode-insert-and-indent) @@ -349,6 +367,18 @@ STOP-AT-STRING is not true, over strings." (- (point-max) (point-min)))) +(defun go--match-raw-string-literal (end) + "Search for a raw string literal. Set point to the end of the +occurence found on success. Returns nil on failure." + (when (search-forward "`" end t) + (goto-char (match-beginning 0)) + (if (go-in-string-or-comment-p) + (progn (goto-char (match-end 0)) + (go--match-raw-string-literal end)) + (when (looking-at "\\(`\\)\\([^`]*\\)\\(`\\)") + (goto-char (match-end 0)) + t)))) + (defun go-previous-line-has-dangling-op-p () "Returns non-nil if the current line is a continuation line." (let* ((cur-line (line-number-at-pos)) @@ -450,8 +480,9 @@ current line will be returned." (goto-char (- (point-max) pos)))))) (defun go-beginning-of-defun (&optional count) - (unless count (setq count 1)) - (let ((first t) failure) + (setq count (or count 1)) + (let ((first t) + failure) (dotimes (i (abs count)) (while (and (not failure) (or first (go-in-string-or-comment-p))) @@ -513,7 +544,7 @@ The following extra functions are defined: If you want to automatically run `gofmt' before saving a file, add the following hook to your emacs configuration: -\(add-hook 'before-save-hook 'gofmt-before-save) +\(add-hook 'before-save-hook #'gofmt-before-save) If you want to use `godef-jump' instead of etags (or similar), consider binding godef-jump to `M-.', which is the default key @@ -532,7 +563,8 @@ If you're looking for even more integration with Go, namely on-the-fly syntax checking, auto-completion and snippets, it is recommended that you look at goflymake \(https://github.com/dougm/goflymake), gocode -\(https://github.com/nsf/gocode) and yasnippet-go +\(https://github.com/nsf/gocode), go-eldoc +\(github.com/syohex/emacs-go-eldoc) and yasnippet-go \(https://github.com/dominikh/yasnippet-go)" ;; Font lock @@ -553,11 +585,16 @@ recommended that you look at goflymake (set (make-local-variable 'parse-sexp-lookup-properties) t) (if (boundp 'syntax-propertize-function) - (set (make-local-variable 'syntax-propertize-function) #'go-propertize-syntax)) + (set (make-local-variable 'syntax-propertize-function) #'go-propertize-syntax) + (set (make-local-variable 'font-lock-syntactic-keywords) + go--font-lock-syntactic-keywords) + (set (make-local-variable 'font-lock-multiline) t)) (set (make-local-variable 'go-dangling-cache) (make-hash-table :test 'eql)) (add-hook 'before-change-functions (lambda (x y) (setq go-dangling-cache (make-hash-table :test 'eql))) t t) + ;; ff-find-other-file + (setq ff-other-file-alist 'go-other-file-alist) (setq imenu-generic-expression '(("type" "^type *\\([^ \t\n\r\f]*\\)" 1) @@ -992,7 +1029,7 @@ description at POINT." "-f" (file-truename (buffer-file-name (go--coverage-origin-buffer))) "-o" - (number-to-string (go--position-bytes (point)))) + (number-to-string (go--position-bytes point))) (with-current-buffer outbuf (split-string (buffer-substring-no-properties (point-min) (point-max)) "\n"))))) @@ -1108,7 +1145,7 @@ divisor for FILE-NAME." (start-line start-column end-line end-column num count) (mapcar #'string-to-number rest) - (when (and (string= (file-name-nondirectory file) file-name)) + (when (string= (file-name-nondirectory file) file-name) (if (> count max-count) (setq max-count count)) (push (make-go--covered :start-line start-line diff --git a/misc/goplay/Makefile b/misc/goplay/Makefile deleted file mode 100644 index a6db75ac3..000000000 --- a/misc/goplay/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# 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. - -goplay: goplay.go - go build goplay.go diff --git a/misc/goplay/README b/misc/goplay/README deleted file mode 100644 index e8a1d290f..000000000 --- a/misc/goplay/README +++ /dev/null @@ -1 +0,0 @@ -See doc.go. diff --git a/misc/goplay/doc.go b/misc/goplay/doc.go deleted file mode 100644 index 61e74a000..000000000 --- a/misc/goplay/doc.go +++ /dev/null @@ -1,23 +0,0 @@ -// 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. - -// Goplay is a web interface for experimenting with Go code. -// It is similar to the Go Playground: http://golang.org/doc/play/ -// -// To use goplay: -// $ cd $GOROOT/misc/goplay -// $ go run goplay.go -// and load http://localhost:3999/ in a web browser. -// -// You should see a Hello World program, which you can compile and run by -// pressing shift-enter. There is also a "compile-on-keypress" feature that can -// be enabled by checking a checkbox. -// -// WARNING! CUIDADO! ACHTUNG! ATTENZIONE! -// A note on security: anyone with access to the goplay web interface can run -// arbitrary code on your computer. Goplay is not a sandbox, and has no other -// security mechanisms. Do not deploy it in untrusted environments. -// By default, goplay listens only on localhost. This can be overridden with -// the -http parameter. Do so at your own risk. -package main diff --git a/misc/goplay/goplay.go b/misc/goplay/goplay.go deleted file mode 100644 index 9cb7d7bfb..000000000 --- a/misc/goplay/goplay.go +++ /dev/null @@ -1,288 +0,0 @@ -// 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 ( - "bytes" - "flag" - "io/ioutil" - "log" - "net/http" - "os" - "os/exec" - "path/filepath" - "regexp" - "strconv" - "text/template" -) - -var ( - httpListen = flag.String("http", "127.0.0.1:3999", "host:port to listen on") - htmlOutput = flag.Bool("html", false, "render program output as HTML") -) - -var ( - // a source of numbers, for naming temporary files - uniq = make(chan int) -) - -func main() { - flag.Parse() - - // source of unique numbers - go func() { - for i := 0; ; i++ { - uniq <- i - } - }() - - http.HandleFunc("/", FrontPage) - http.HandleFunc("/compile", Compile) - log.Fatal(http.ListenAndServe(*httpListen, nil)) -} - -// FrontPage is an HTTP handler that renders the goplay interface. -// If a filename is supplied in the path component of the URI, -// its contents will be put in the interface's text area. -// Otherwise, the default "hello, world" program is displayed. -func FrontPage(w http.ResponseWriter, req *http.Request) { - data, err := ioutil.ReadFile(req.URL.Path[1:]) - if err != nil { - data = helloWorld - } - frontPage.Execute(w, data) -} - -// Compile is an HTTP handler that reads Go source code from the request, -// runs the program (returning any errors), -// and sends the program's output as the HTTP response. -func Compile(w http.ResponseWriter, req *http.Request) { - out, err := compile(req) - if err != nil { - error_(w, out, err) - return - } - - // write the output of x as the http response - if *htmlOutput { - w.Write(out) - } else { - output.Execute(w, out) - } -} - -var ( - commentRe = regexp.MustCompile(`(?m)^#.*\n`) - tmpdir string -) - -func init() { - // find real temporary directory (for rewriting filename in output) - var err error - tmpdir, err = filepath.EvalSymlinks(os.TempDir()) - if err != nil { - log.Fatal(err) - } -} - -func compile(req *http.Request) (out []byte, err error) { - // x is the base name for .go, .6, executable files - x := filepath.Join(tmpdir, "compile"+strconv.Itoa(<-uniq)) - src := x + ".go" - - // rewrite filename in error output - defer func() { - if err != nil { - // drop messages from the go tool like '# _/compile0' - out = commentRe.ReplaceAll(out, nil) - } - out = bytes.Replace(out, []byte(src+":"), []byte("main.go:"), -1) - }() - - // write body to x.go - body := new(bytes.Buffer) - if _, err = body.ReadFrom(req.Body); err != nil { - return - } - defer os.Remove(src) - if err = ioutil.WriteFile(src, body.Bytes(), 0666); err != nil { - return - } - - // go run x.go - dir, file := filepath.Split(src) - out, err = run(dir, "go", "run", file) - if err != nil { - return - } - return out, nil -} - -// error writes compile, link, or runtime errors to the HTTP connection. -// The JavaScript interface uses the 404 status code to identify the error. -func error_(w http.ResponseWriter, out []byte, err error) { - w.WriteHeader(404) - if out != nil { - output.Execute(w, out) - } else { - output.Execute(w, err.Error()) - } -} - -// run executes the specified command and returns its output and an error. -func run(dir string, args ...string) ([]byte, error) { - var buf bytes.Buffer - cmd := exec.Command(args[0], args[1:]...) - cmd.Dir = dir - cmd.Stdout = &buf - cmd.Stderr = cmd.Stdout - err := cmd.Run() - return buf.Bytes(), err -} - -var frontPage = template.Must(template.New("frontPage").Parse(frontPageText)) // HTML template -var output = template.Must(template.New("output").Parse(outputText)) // HTML template - -var outputText = `

    {{printf "%s" . |html}}
    ` - -var frontPageText = ` - - - - - - -
    - -
    -(Shift-Enter to compile and run.)     - Compile and run after each keystroke -
    -
    - -
    -
    -
    - - -` - -var helloWorld = []byte(`package main - -import "fmt" - -func main() { - fmt.Println("hello, world") -} -`) diff --git a/misc/makerelease/darwin/Distribution b/misc/makerelease/darwin/Distribution new file mode 100644 index 000000000..8b764b69f --- /dev/null +++ b/misc/makerelease/darwin/Distribution @@ -0,0 +1,32 @@ + + + Go + + + + + + + + + + + + com.googlecode.go.pkg + diff --git a/misc/makerelease/darwin/Resources/bg.png b/misc/makerelease/darwin/Resources/bg.png new file mode 100644 index 000000000..c3d8ea93a Binary files /dev/null and b/misc/makerelease/darwin/Resources/bg.png differ diff --git a/misc/makerelease/darwin/etc/paths.d/go b/misc/makerelease/darwin/etc/paths.d/go new file mode 100644 index 000000000..532e5f936 --- /dev/null +++ b/misc/makerelease/darwin/etc/paths.d/go @@ -0,0 +1 @@ +/usr/local/go/bin diff --git a/misc/makerelease/darwin/scripts/postinstall b/misc/makerelease/darwin/scripts/postinstall new file mode 100755 index 000000000..13f5bff9b --- /dev/null +++ b/misc/makerelease/darwin/scripts/postinstall @@ -0,0 +1,10 @@ +#!/bin/bash + +GOROOT=/usr/local/go + +echo "Fixing permissions" +cd $GOROOT +find . -exec chmod ugo+r \{\} \; +find bin -exec chmod ugo+rx \{\} \; +find . -type d -exec chmod ugo+rx \{\} \; +chmod o-w . diff --git a/misc/makerelease/darwin/scripts/preinstall b/misc/makerelease/darwin/scripts/preinstall new file mode 100755 index 000000000..4cdaaa4bc --- /dev/null +++ b/misc/makerelease/darwin/scripts/preinstall @@ -0,0 +1,8 @@ +#!/bin/bash + +GOROOT=/usr/local/go + +echo "Removing previous installation" +if [ -d $GOROOT ]; then + rm -r $GOROOT +fi diff --git a/misc/makerelease/makerelease.go b/misc/makerelease/makerelease.go new file mode 100644 index 000000000..2496a865a --- /dev/null +++ b/misc/makerelease/makerelease.go @@ -0,0 +1,1030 @@ +// Copyright 2012 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 is a tool for packaging binary releases. +// It supports FreeBSD, Linux, NetBSD, OpenBSD, OS X, and Windows. +package main + +import ( + "archive/tar" + "archive/zip" + "bufio" + "bytes" + "compress/gzip" + "crypto/sha1" + "encoding/json" + "flag" + "fmt" + "io" + "io/ioutil" + "log" + "net/http" + "net/url" + "os" + "os/exec" + "path" + "path/filepath" + "regexp" + "runtime" + "strings" + + "code.google.com/p/goauth2/oauth" + "code.google.com/p/google-api-go-client/storage/v1beta2" +) + +var ( + tag = flag.String("tag", "release", "mercurial tag to check out") + toolTag = flag.String("tool", defaultToolTag, "go.tools tag to check out") + tourTag = flag.String("tour", defaultTourTag, "go-tour tag to check out") + repo = flag.String("repo", "https://code.google.com/p/go", "repo URL") + verbose = flag.Bool("v", false, "verbose output") + upload = flag.Bool("upload", false, "upload resulting files to Google Code") + addLabel = flag.String("label", "", "additional label to apply to file when uploading") + includeRace = flag.Bool("race", true, "build race detector packages") + versionOverride = flag.String("version", "", "override version name") + staticToolchain = flag.Bool("static", true, "try to build statically linked toolchain (only supported on ELF targets)") + tokenCache = flag.String("token", defaultCacheFile, "Authentication token cache file") + storageBucket = flag.String("bucket", "golang", "Cloud Storage Bucket") + uploadURL = flag.String("upload_url", defaultUploadURL, "Upload URL") + + defaultCacheFile = filepath.Join(os.Getenv("HOME"), ".makerelease-request-token") + defaultUploadURL = "http://golang.org/dl/upload" +) + +const ( + blogPath = "code.google.com/p/go.blog" + toolPath = "code.google.com/p/go.tools" + tourPath = "code.google.com/p/go-tour" + defaultToolTag = "release-branch.go1.2" + defaultTourTag = "release-branch.go1.2" +) + +// Import paths for tool commands. +// These must be the command that cmd/go knows to install to $GOROOT/bin +// or $GOROOT/pkg/tool. +var toolPaths = []string{ + "code.google.com/p/go.tools/cmd/cover", + "code.google.com/p/go.tools/cmd/godoc", + "code.google.com/p/go.tools/cmd/vet", +} + +var preBuildCleanFiles = []string{ + "lib/codereview", + "misc/dashboard/godashboard", + "src/cmd/cov", + "src/cmd/prof", + "src/pkg/exp", + "src/pkg/old", +} + +var cleanFiles = []string{ + ".hg", + ".hgtags", + ".hgignore", + "VERSION.cache", +} + +var sourceCleanFiles = []string{ + "bin", + "pkg", +} + +var tourPackages = []string{ + "pic", + "tree", + "wc", +} + +var tourContent = []string{ + "content", + "solutions", + "static", + "template", +} + +var blogContent = []string{ + "content", + "template", +} + +// The os-arches that support the race toolchain. +var raceAvailable = []string{ + "darwin-amd64", + "linux-amd64", + "windows-amd64", +} + +// The OSes that support building statically linked toolchain +// Only ELF platforms are supported. +var staticLinkAvailable = []string{ + "linux", + "freebsd", + "openbsd", + "netbsd", +} + +var fileRe = regexp.MustCompile(`^(go[a-z0-9-.]+)\.(src|([a-z0-9]+)-([a-z0-9]+)(?:-([a-z0-9.]+))?)\.(tar\.gz|zip|pkg|msi)$`) + +// OAuth2-authenticated HTTP client used to make calls to Cloud Storage. +var oauthClient *http.Client + +// Builder key as specified in ~/.gobuildkey +var builderKey string + +func main() { + flag.Usage = func() { + fmt.Fprintf(os.Stderr, "usage: %s [flags] targets...\n", os.Args[0]) + flag.PrintDefaults() + os.Exit(2) + } + flag.Parse() + if flag.NArg() == 0 { + flag.Usage() + } + if runtime.GOOS == "windows" { + checkWindowsDeps() + } + + if *upload { + if err := readCredentials(); err != nil { + log.Fatalln("readCredentials:", err) + } + if err := setupOAuthClient(); err != nil { + log.Fatalln("setupOAuthClient:", err) + } + } + for _, targ := range flag.Args() { + var b Build + if m := fileRe.FindStringSubmatch(targ); m != nil { + // targ is a file name; upload it to googlecode. + version := m[1] + if m[2] == "src" { + b.Source = true + } else { + b.OS = m[3] + b.Arch = m[4] + b.Label = m[5] + } + if !*upload { + log.Printf("%s: -upload=false, skipping", targ) + continue + } + if err := b.Upload(version, targ); err != nil { + log.Printf("uploading %s: %v", targ, err) + } + continue + } + if targ == "source" { + b.Source = true + } else { + p := strings.SplitN(targ, "-", 3) + if len(p) < 2 { + log.Println("Ignoring unrecognized target:", targ) + continue + } + b.OS = p[0] + b.Arch = p[1] + if len(p) >= 3 { + b.Label = p[2] + } + if *includeRace { + for _, t := range raceAvailable { + if t == targ || strings.HasPrefix(targ, t+"-") { + b.Race = true + } + } + } + if *staticToolchain { + for _, os := range staticLinkAvailable { + if b.OS == os { + b.static = true + } + } + } + } + if err := b.Do(); err != nil { + log.Printf("%s: %v", targ, err) + } + } +} + +type Build struct { + Source bool // if true, OS and Arch must be empty + Race bool // build race toolchain + OS string + Arch string + Label string + root string + gopath string + static bool // if true, build statically linked toolchain +} + +func (b *Build) Do() error { + work, err := ioutil.TempDir("", "makerelease") + if err != nil { + return err + } + defer os.RemoveAll(work) + b.root = filepath.Join(work, "go") + b.gopath = work + + // Clone Go distribution and update to tag. + _, err = b.hgCmd(work, "clone", *repo, b.root) + if err != nil { + return err + } + _, err = b.hgCmd(b.root, "update", *tag) + if err != nil { + return err + } + + // Remove exp and old packages. + if err := b.clean(preBuildCleanFiles); err != nil { + return err + } + + src := filepath.Join(b.root, "src") + if b.Source { + if runtime.GOOS == "windows" { + log.Print("Warning: running make.bash on Windows; source builds are intended to be run on a Unix machine") + } + // Build dist tool only. + _, err = b.run(src, "bash", "make.bash", "--dist-tool") + } else { + // Build. + if b.OS == "windows" { + _, err = b.run(src, "cmd", "/C", "make.bat") + } else { + _, err = b.run(src, "bash", "make.bash") + } + if b.Race { + if err != nil { + return err + } + goCmd := filepath.Join(b.root, "bin", "go") + if b.OS == "windows" { + goCmd += ".exe" + } + _, err = b.run(src, goCmd, "install", "-race", "std") + if err != nil { + return err + } + // Re-install std without -race, so that we're not left + // with a slower, race-enabled cmd/go, etc. + _, err = b.run(src, goCmd, "install", "-a", "std") + // Re-building go command leaves old versions of go.exe as go.exe~ on windows. + // See (*builder).copyFile in $GOROOT/src/cmd/go/build.go for details. + // Remove it manually. + if b.OS == "windows" { + os.Remove(goCmd + "~") + } + } + if err != nil { + return err + } + err = b.extras() + } + if err != nil { + return err + } + + // Get version strings. + var ( + version string // "weekly.2012-03-04" + fullVersion []byte // "weekly.2012-03-04 9353aa1efdf3" + ) + pat := filepath.Join(b.root, "pkg/tool/*/dist*") // trailing * for .exe + m, err := filepath.Glob(pat) + if err != nil { + return err + } + if len(m) == 0 { + return fmt.Errorf("couldn't find dist in %q", pat) + } + fullVersion, err = b.run("", m[0], "version") + if err != nil { + return err + } + fullVersion = bytes.TrimSpace(fullVersion) + v := bytes.SplitN(fullVersion, []byte(" "), 2) + version = string(v[0]) + if *versionOverride != "" { + version = *versionOverride + } + + // Write VERSION file. + err = ioutil.WriteFile(filepath.Join(b.root, "VERSION"), fullVersion, 0644) + if err != nil { + return err + } + + // Clean goroot. + if err := b.clean(cleanFiles); err != nil { + return err + } + if b.Source { + if err := b.clean(sourceCleanFiles); err != nil { + return err + } + } + + // Create packages. + base := fmt.Sprintf("%s.%s-%s", version, b.OS, b.Arch) + if b.Label != "" { + base += "-" + b.Label + } + if !strings.HasPrefix(base, "go") { + base = "go." + base + } + var targs []string + switch b.OS { + case "linux", "freebsd", "netbsd", "": + // build tarball + targ := base + if b.Source { + targ = fmt.Sprintf("%s.src", version) + if !strings.HasPrefix(targ, "go") { + targ = "go." + targ + } + } + targ += ".tar.gz" + err = makeTar(targ, work) + targs = append(targs, targ) + case "darwin": + // build tarball + targ := base + ".tar.gz" + err = makeTar(targ, work) + targs = append(targs, targ) + + makerelease := filepath.Join(runtime.GOROOT(), "misc/makerelease") + + // build pkg + // arrange work so it's laid out as the dest filesystem + etc := filepath.Join(makerelease, "darwin/etc") + _, err = b.run(work, "cp", "-r", etc, ".") + if err != nil { + return err + } + localDir := filepath.Join(work, "usr/local") + err = os.MkdirAll(localDir, 0755) + if err != nil { + return err + } + _, err = b.run(work, "mv", "go", localDir) + if err != nil { + return err + } + // build package + pkgdest, err := ioutil.TempDir("", "pkgdest") + if err != nil { + return err + } + defer os.RemoveAll(pkgdest) + _, err = b.run("", "pkgbuild", + "--identifier", "com.googlecode.go", + "--version", version, + "--scripts", filepath.Join(makerelease, "darwin/scripts"), + "--root", work, + filepath.Join(pkgdest, "com.googlecode.go.pkg")) + if err != nil { + return err + } + targ = base + ".pkg" + _, err = b.run("", "productbuild", + "--distribution", filepath.Join(makerelease, "darwin/Distribution"), + "--resources", filepath.Join(makerelease, "darwin/Resources"), + "--package-path", pkgdest, + targ) + if err != nil { + return err + } + targs = append(targs, targ) + case "windows": + // Create ZIP file. + zip := filepath.Join(work, base+".zip") + err = makeZip(zip, work) + // Copy zip to target file. + targ := base + ".zip" + err = cp(targ, zip) + if err != nil { + return err + } + targs = append(targs, targ) + + // Create MSI installer. + win := filepath.Join(runtime.GOROOT(), "misc/makerelease/windows") + installer := filepath.Join(win, "installer.wxs") + appfiles := filepath.Join(work, "AppFiles.wxs") + msi := filepath.Join(work, "installer.msi") + // Gather files. + _, err = b.run(work, "heat", "dir", "go", + "-nologo", + "-gg", "-g1", "-srd", "-sfrag", + "-cg", "AppFiles", + "-template", "fragment", + "-dr", "INSTALLDIR", + "-var", "var.SourceDir", + "-out", appfiles) + if err != nil { + return err + } + // Build package. + _, err = b.run(work, "candle", + "-nologo", + "-dVersion="+version, + "-dArch="+b.Arch, + "-dSourceDir=go", + installer, appfiles) + if err != nil { + return err + } + appfiles = filepath.Join(work, "AppFiles.wixobj") + installer = filepath.Join(work, "installer.wixobj") + _, err = b.run(win, "light", + "-nologo", + "-ext", "WixUIExtension", + "-ext", "WixUtilExtension", + installer, appfiles, + "-o", msi) + if err != nil { + return err + } + // Copy installer to target file. + targ = base + ".msi" + err = cp(targ, msi) + targs = append(targs, targ) + } + if err == nil && *upload { + for _, targ := range targs { + err = b.Upload(version, targ) + if err != nil { + return fmt.Errorf("uploading %s: %v", targ, err) + } + } + } + return err +} + +// extras fetches the go.tools, go.blog, and go-tour repositories, +// builds them and copies the resulting binaries and static assets +// to the new GOROOT. +func (b *Build) extras() error { + defer b.cleanGopath() + + if err := b.tools(); err != nil { + return err + } + if err := b.blog(); err != nil { + return err + } + return b.tour() +} + +func (b *Build) get(repoPath, revision string) error { + // Fetch the packages (without building/installing). + _, err := b.run(b.gopath, filepath.Join(b.root, "bin", "go"), + "get", "-d", repoPath+"/...") + if err != nil { + return err + } + + // Update the repo to the specified revision. + p := filepath.Join(b.gopath, "src", filepath.FromSlash(repoPath)) + _, err = b.run(p, "hg", "update", revision) + return err +} + +func (b *Build) tools() error { + // Fetch the go.tools repository. + if err := b.get(toolPath, *toolTag); err != nil { + return err + } + + // Install tools. + args := append([]string{"install"}, toolPaths...) + _, err := b.run(b.gopath, filepath.Join(b.root, "bin", "go"), args...) + if err != nil { + return err + } + + // Copy doc.go from go.tools/cmd/$CMD to $GOROOT/src/cmd/$CMD + // while rewriting "package main" to "package documentation". + for _, p := range toolPaths { + d, err := ioutil.ReadFile(filepath.Join(b.gopath, "src", + filepath.FromSlash(p), "doc.go")) + if err != nil { + return err + } + d = bytes.Replace(d, []byte("\npackage main\n"), + []byte("\npackage documentation\n"), 1) + cmdDir := filepath.Join(b.root, "src", "cmd", path.Base(p)) + if err := os.MkdirAll(cmdDir, 0755); err != nil { + return err + } + docGo := filepath.Join(cmdDir, "doc.go") + if err := ioutil.WriteFile(docGo, d, 0644); err != nil { + return err + } + } + + return nil +} + +func (b *Build) blog() error { + // Fetch the blog repository. + _, err := b.run(b.gopath, filepath.Join(b.root, "bin", "go"), "get", "-d", blogPath+"/blog") + if err != nil { + return err + } + + // Copy blog content to $GOROOT/blog. + blogSrc := filepath.Join(b.gopath, "src", filepath.FromSlash(blogPath)) + contentDir := filepath.Join(b.root, "blog") + return cpAllDir(contentDir, blogSrc, blogContent...) +} + +func (b *Build) tour() error { + // Fetch the go-tour repository. + if err := b.get(tourPath, *tourTag); err != nil { + return err + } + + // Build tour binary. + _, err := b.run(b.gopath, filepath.Join(b.root, "bin", "go"), + "install", tourPath+"/gotour") + if err != nil { + return err + } + + // Copy all the tour content to $GOROOT/misc/tour. + importPath := filepath.FromSlash(tourPath) + tourSrc := filepath.Join(b.gopath, "src", importPath) + contentDir := filepath.Join(b.root, "misc", "tour") + if err = cpAllDir(contentDir, tourSrc, tourContent...); err != nil { + return err + } + + // Copy the tour source code so it's accessible with $GOPATH pointing to $GOROOT/misc/tour. + if err = cpAllDir(filepath.Join(contentDir, "src", importPath), tourSrc, tourPackages...); err != nil { + return err + } + + // Copy gotour binary to tool directory as "tour"; invoked as "go tool tour". + return cp( + filepath.Join(b.root, "pkg", "tool", b.OS+"_"+b.Arch, "tour"+ext()), + filepath.Join(b.gopath, "bin", "gotour"+ext()), + ) +} + +func (b *Build) cleanGopath() { + for _, d := range []string{"bin", "pkg", "src"} { + os.RemoveAll(filepath.Join(b.gopath, d)) + } +} + +func ext() string { + if runtime.GOOS == "windows" { + return ".exe" + } + return "" +} + +func (b *Build) hgCmd(dir string, args ...string) ([]byte, error) { + return b.run(dir, "hg", append([]string{"--config", "extensions.codereview=!"}, args...)...) +} + +func (b *Build) run(dir, name string, args ...string) ([]byte, error) { + buf := new(bytes.Buffer) + absName, err := lookPath(name) + if err != nil { + return nil, err + } + cmd := exec.Command(absName, args...) + var output io.Writer = buf + if *verbose { + log.Printf("Running %q %q", absName, args) + output = io.MultiWriter(buf, os.Stdout) + } + cmd.Stdout = output + cmd.Stderr = output + cmd.Dir = dir + cmd.Env = b.env() + if err := cmd.Run(); err != nil { + fmt.Fprintf(os.Stderr, "%s", buf.Bytes()) + return nil, fmt.Errorf("%s %s: %v", name, strings.Join(args, " "), err) + } + return buf.Bytes(), nil +} + +var cleanEnv = []string{ + "GOARCH", + "GOBIN", + "GOHOSTARCH", + "GOHOSTOS", + "GOOS", + "GOROOT", + "GOROOT_FINAL", + "GOPATH", +} + +func (b *Build) env() []string { + env := os.Environ() + for i := 0; i < len(env); i++ { + for _, c := range cleanEnv { + if strings.HasPrefix(env[i], c+"=") { + env = append(env[:i], env[i+1:]...) + } + } + } + final := "/usr/local/go" + if b.OS == "windows" { + final = `c:\go` + } + env = append(env, + "GOARCH="+b.Arch, + "GOHOSTARCH="+b.Arch, + "GOHOSTOS="+b.OS, + "GOOS="+b.OS, + "GOROOT="+b.root, + "GOROOT_FINAL="+final, + "GOPATH="+b.gopath, + ) + if b.static { + env = append(env, "GO_DISTFLAGS=-s") + } + return env +} + +func (b *Build) Upload(version string, filename string) error { + file, err := ioutil.ReadFile(filename) + if err != nil { + return err + } + + svc, err := storage.New(oauthClient) + if err != nil { + return err + } + obj := &storage.Object{ + Acl: []*storage.ObjectAccessControl{{Entity: "allUsers", Role: "READER"}}, + Name: filename, + } + _, err = svc.Objects.Insert(*storageBucket, obj).Media(bytes.NewReader(file)).Do() + if err != nil { + return err + } + + sum := fmt.Sprintf("%x", sha1.Sum(file)) + kind := "unknown" + switch { + case b.Source: + kind = "source" + case strings.HasSuffix(filename, ".tar.gz"), strings.HasSuffix(filename, ".zip"): + kind = "archive" + case strings.HasSuffix(filename, ".msi"), strings.HasSuffix(filename, ".pkg"): + kind = "installer" + } + req, err := json.Marshal(File{ + Filename: filename, + Version: version, + OS: b.OS, + Arch: b.Arch, + Checksum: sum, + Kind: kind, + }) + if err != nil { + return err + } + u := fmt.Sprintf("%s?%s", *uploadURL, url.Values{"key": []string{builderKey}}.Encode()) + resp, err := http.Post(u, "application/json", bytes.NewReader(req)) + if err != nil { + return err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("upload status: %v", resp.Status) + } + + return nil +} + +type File struct { + Filename string + OS string + Arch string + Version string + Checksum string `datastore:",noindex"` + Kind string // "archive", "installer", "source" +} + +func setupOAuthClient() error { + config := &oauth.Config{ + ClientId: "999119582588-h7kpj5pcm6d9solh5lgrbusmvvk4m9dn.apps.googleusercontent.com", + ClientSecret: "8YLFgOhXIELWbO", + Scope: storage.DevstorageRead_writeScope, + AuthURL: "https://accounts.google.com/o/oauth2/auth", + TokenURL: "https://accounts.google.com/o/oauth2/token", + TokenCache: oauth.CacheFile(*tokenCache), + RedirectURL: "oob", + } + transport := &oauth.Transport{Config: config} + if token, err := config.TokenCache.Token(); err != nil { + url := transport.Config.AuthCodeURL("") + fmt.Println("Visit the following URL, obtain an authentication" + + "code, and enter it below.") + fmt.Println(url) + fmt.Print("Enter authentication code: ") + code := "" + if _, err := fmt.Scan(&code); err != nil { + return err + } + if _, err := transport.Exchange(code); err != nil { + return err + } + } else { + transport.Token = token + } + oauthClient = transport.Client() + return nil +} + +func (b *Build) clean(files []string) error { + for _, name := range files { + err := os.RemoveAll(filepath.Join(b.root, name)) + if err != nil { + return err + } + } + return nil +} + +func exists(path string) bool { + _, err := os.Stat(path) + return err == nil +} + +func readCredentials() error { + name := os.Getenv("HOME") + if runtime.GOOS == "windows" { + name = os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH") + } + name = filepath.Join(name, ".gobuildkey") + f, err := os.Open(name) + if err != nil { + return err + } + defer f.Close() + s := bufio.NewScanner(f) + if s.Scan() { + builderKey = s.Text() + } + return s.Err() +} + +func cp(dst, src string) error { + sf, err := os.Open(src) + if err != nil { + return err + } + defer sf.Close() + fi, err := sf.Stat() + if err != nil { + return err + } + df, err := os.Create(dst) + if err != nil { + return err + } + defer df.Close() + // Windows doesn't currently implement Fchmod + if runtime.GOOS != "windows" { + if err := df.Chmod(fi.Mode()); err != nil { + return err + } + } + _, err = io.Copy(df, sf) + return err +} + +func cpDir(dst, src string) error { + walk := func(srcPath string, info os.FileInfo, err error) error { + if err != nil { + return err + } + dstPath := filepath.Join(dst, srcPath[len(src):]) + if info.IsDir() { + return os.MkdirAll(dstPath, 0755) + } + return cp(dstPath, srcPath) + } + return filepath.Walk(src, walk) +} + +func cpAllDir(dst, basePath string, dirs ...string) error { + for _, dir := range dirs { + if err := cpDir(filepath.Join(dst, dir), filepath.Join(basePath, dir)); err != nil { + return err + } + } + return nil +} + +func makeTar(targ, workdir string) error { + f, err := os.Create(targ) + if err != nil { + return err + } + zout := gzip.NewWriter(f) + tw := tar.NewWriter(zout) + + err = filepath.Walk(workdir, func(path string, fi os.FileInfo, err error) error { + if !strings.HasPrefix(path, workdir) { + log.Panicf("walked filename %q doesn't begin with workdir %q", path, workdir) + } + name := path[len(workdir):] + + // Chop of any leading / from filename, leftover from removing workdir. + if strings.HasPrefix(name, "/") { + name = name[1:] + } + // Don't include things outside of the go subdirectory (for instance, + // the zip file that we're currently writing here.) + if !strings.HasPrefix(name, "go/") { + return nil + } + if *verbose { + log.Printf("adding to tar: %s", name) + } + target, _ := os.Readlink(path) + hdr, err := tar.FileInfoHeader(fi, target) + if err != nil { + return err + } + hdr.Name = name + hdr.Uname = "root" + hdr.Gname = "root" + hdr.Uid = 0 + hdr.Gid = 0 + + // Force permissions to 0755 for executables, 0644 for everything else. + if fi.Mode().Perm()&0111 != 0 { + hdr.Mode = hdr.Mode&^0777 | 0755 + } else { + hdr.Mode = hdr.Mode&^0777 | 0644 + } + + err = tw.WriteHeader(hdr) + if err != nil { + return fmt.Errorf("Error writing file %q: %v", name, err) + } + if fi.IsDir() { + return nil + } + r, err := os.Open(path) + if err != nil { + return err + } + defer r.Close() + _, err = io.Copy(tw, r) + return err + }) + if err != nil { + return err + } + if err := tw.Close(); err != nil { + return err + } + if err := zout.Close(); err != nil { + return err + } + return f.Close() +} + +func makeZip(targ, workdir string) error { + f, err := os.Create(targ) + if err != nil { + return err + } + zw := zip.NewWriter(f) + + err = filepath.Walk(workdir, func(path string, fi os.FileInfo, err error) error { + if !strings.HasPrefix(path, workdir) { + log.Panicf("walked filename %q doesn't begin with workdir %q", path, workdir) + } + name := path[len(workdir):] + + // Convert to Unix-style named paths, as that's the + // type of zip file that archive/zip creates. + name = strings.Replace(name, "\\", "/", -1) + // Chop of any leading / from filename, leftover from removing workdir. + if strings.HasPrefix(name, "/") { + name = name[1:] + } + // Don't include things outside of the go subdirectory (for instance, + // the zip file that we're currently writing here.) + if !strings.HasPrefix(name, "go/") { + return nil + } + if *verbose { + log.Printf("adding to zip: %s", name) + } + fh, err := zip.FileInfoHeader(fi) + if err != nil { + return err + } + fh.Name = name + fh.Method = zip.Deflate + if fi.IsDir() { + fh.Name += "/" // append trailing slash + fh.Method = zip.Store // no need to deflate 0 byte files + } + w, err := zw.CreateHeader(fh) + if err != nil { + return err + } + if fi.IsDir() { + return nil + } + r, err := os.Open(path) + if err != nil { + return err + } + defer r.Close() + _, err = io.Copy(w, r) + return err + }) + if err != nil { + return err + } + if err := zw.Close(); err != nil { + return err + } + return f.Close() +} + +type tool struct { + name string + commonDirs []string +} + +var wixTool = tool{ + "http://wix.sourceforge.net/, version 3.5", + []string{`C:\Program Files\Windows Installer XML v3.5\bin`, + `C:\Program Files (x86)\Windows Installer XML v3.5\bin`}, +} + +var hgTool = tool{ + "http://mercurial.selenic.com/wiki/WindowsInstall", + []string{`C:\Program Files\Mercurial`, + `C:\Program Files (x86)\Mercurial`, + }, +} + +var gccTool = tool{ + "Mingw gcc; http://sourceforge.net/projects/mingw/files/Installer/mingw-get-inst/", + []string{`C:\Mingw\bin`}, +} + +var windowsDeps = map[string]tool{ + "gcc": gccTool, + "heat": wixTool, + "candle": wixTool, + "light": wixTool, + "cmd": {"Windows cmd.exe", nil}, + "hg": hgTool, +} + +func checkWindowsDeps() { + for prog, help := range windowsDeps { + absPath, err := lookPath(prog) + if err != nil { + log.Fatalf("Failed to find necessary binary %q in path or common locations; %s", prog, help) + } + if *verbose { + log.Printf("found windows dep %s at %s", prog, absPath) + } + } +} + +func lookPath(prog string) (absPath string, err error) { + absPath, err = exec.LookPath(prog) + if err == nil { + return + } + t, ok := windowsDeps[prog] + if !ok { + return + } + for _, dir := range t.commonDirs { + for _, ext := range []string{"exe", "bat"} { + absPath = filepath.Join(dir, prog+"."+ext) + if _, err1 := os.Stat(absPath); err1 == nil { + err = nil + os.Setenv("PATH", os.Getenv("PATH")+";"+dir) + return + } + } + } + return +} diff --git a/misc/makerelease/windows/LICENSE.rtf b/misc/makerelease/windows/LICENSE.rtf new file mode 100644 index 000000000..b2b0be62c Binary files /dev/null and b/misc/makerelease/windows/LICENSE.rtf differ diff --git a/misc/makerelease/windows/README.txt b/misc/makerelease/windows/README.txt new file mode 100644 index 000000000..0cf828b24 --- /dev/null +++ b/misc/makerelease/windows/README.txt @@ -0,0 +1,25 @@ + +Windows build dependencies + +- Mercurial (hg): http://mercurial.selenic.com/ +- MinGW: http://www.mingw.org/ +- Windows Installer XML (WiX) toolset: http://wix.sourceforge.net/ + +Packaging + +The dependencies must be in/added to the system's search PATH. + +Run bindist as normal, eg: + bindist windows-386 + +TODO + +- Documentation server shortcut checkbox option + +Misc + +WiX box sizes: + - banner size: 493x58 + - left side of dialog: 164x312 + - full dialog size: 493x312 + diff --git a/misc/makerelease/windows/images/Banner.jpg b/misc/makerelease/windows/images/Banner.jpg new file mode 100644 index 000000000..ce65f63af Binary files /dev/null and b/misc/makerelease/windows/images/Banner.jpg differ diff --git a/misc/makerelease/windows/images/Dialog.jpg b/misc/makerelease/windows/images/Dialog.jpg new file mode 100644 index 000000000..1f0ec0a31 Binary files /dev/null and b/misc/makerelease/windows/images/Dialog.jpg differ diff --git a/misc/makerelease/windows/images/DialogLeft.jpg b/misc/makerelease/windows/images/DialogLeft.jpg new file mode 100644 index 000000000..73bab89b4 Binary files /dev/null and b/misc/makerelease/windows/images/DialogLeft.jpg differ diff --git a/misc/makerelease/windows/images/gopher.ico b/misc/makerelease/windows/images/gopher.ico new file mode 100644 index 000000000..2e861ebe0 Binary files /dev/null and b/misc/makerelease/windows/images/gopher.ico differ diff --git a/misc/makerelease/windows/installer.wxs b/misc/makerelease/windows/installer.wxs new file mode 100644 index 000000000..b170b98dc --- /dev/null +++ b/misc/makerelease/windows/installer.wxs @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + VersionNT >= 500 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/misc/nacl/README b/misc/nacl/README new file mode 100644 index 000000000..9cc2bda60 --- /dev/null +++ b/misc/nacl/README @@ -0,0 +1,63 @@ +Native Client +============= + +This document outlines the basics of building and developing the Go runtime and programs in the Native Client (NaCl) environment. + +Go 1.3 supports two architectures + + * nacl/386 which is standard 386. + * nacl/amd64p32 which is a 64 bit architecture, where the address space is limited to a 4gb window. + +For background it is recommended that you read http://golang.org/s/go13nacl. + +Prerequisites +------------- + +Native Client programs are executed inside a sandbox, the NaCl runtime. This runtime must be installed before you can use NaCl programs. + +The NaCl distribution comes with an installer which ensures you have access to the latest version of the runtime. The version tracks the Chrome numbering scheme. + +# Download NaCl + +Download nacl_sdk.zip file from https://developers.google.com/native-client/dev/sdk/download, and unpack it. I chose /opt/nacl_sdk + +# Update + +The zip file contains a small skeleton that can be used to download the correct sdk. These are released every 6-8 weeks, in line with Chrome releases. + + % cd /opt/nacl_sdk + % ./naclsdk update + +At this time pepper_33 is the stable version. If naclsdk downloads a later version, please adjust accordingly. + +The cmd/go helper scripts expect that the runtime loaders, sel_ldr_x86_{32,64} are in your path. I find it easiest to make a symlink from the NaCl distribution to my $GOPATH/bin directory. + + % ln -nfs /opt/nacl_sdk/pepper_33/tools/sel_ldr_x86_32 $GOPATH/bin/sel_ldr_x86_32 + % ln -nfs /opt/nacl_sdk/pepper_33/tools/sel_ldr_x86_64 $GOPATH/bin/sel_ldr_x86_64 + +Support scripts +--------------- + +Symlink the two scripts in this directory into your $PATH, just as you did with NaCl sdk above. + + % ln -nfs $GOROOT/go/misc/nacl/go_nacl_amd64p32_exec $GOPATH/bin/go_nacl_amd64p32_exec + % ln -nfs $GOROOT/go/misc/nacl/go_nacl_386_exec $GOPATH/bin/go_nacl_386_exec + +Building and testing +-------------------- + +Building for NaCl is similar to cross compiling for other platforms. However, as it is not possible to ever build in a `native` NaCl environment, the cmd/go tool has been enhanced to allow the full build, all.bash, to be executed, rather than just the compile stage, make.bash. + +The cmd/go tool knows that if GOOS is set to `nacl` it should not try to execute any binaries itself. Instead it passes their execution to a support script which sets up a Native Client environment and invokes the NaCl sandbox. + +The script's name has a special format, go_$GOOS_$GOARCH_exec, so cmd/go can find it. + +In short, if the support scripts are in place, the cmd/go tool can be used as per normal. + +# Build and test Go for NaCl + +NaCl does not permit direct file system access. Instead, package syscall provides a simulated file system served by in-memory data. The script nacltest.bash is the NaCl equivalent of all.bash. It builds NaCl with an in-memory file system containing files needed for tests, and then it runs the tests. + + % cd go/src + % env GOARCH=amd64p32 ./nacltest.bash + diff --git a/misc/nacl/go_nacl_386_exec b/misc/nacl/go_nacl_386_exec new file mode 100755 index 000000000..9cff63556 --- /dev/null +++ b/misc/nacl/go_nacl_386_exec @@ -0,0 +1,10 @@ +#!/bin/bash + +eval $(go env) + +export NACLENV_GOARCH=$GOARCH +export NACLENV_GOOS=$GOOS +export NACLENV_GOROOT=/go +export NACLENV_NACLPWD=$(pwd | sed "s;$GOROOT;/go;") + +exec sel_ldr_x86_32 -l /dev/null -S -e "$@" diff --git a/misc/nacl/go_nacl_amd64p32_exec b/misc/nacl/go_nacl_amd64p32_exec new file mode 100755 index 000000000..0a5ed651f --- /dev/null +++ b/misc/nacl/go_nacl_amd64p32_exec @@ -0,0 +1,10 @@ +#!/bin/bash + +eval $(go env) + +export NACLENV_GOARCH=$GOARCH +export NACLENV_GOOS=$GOOS +export NACLENV_GOROOT=/go +export NACLENV_NACLPWD=$(pwd | sed "s;$GOROOT;/go;") + +exec sel_ldr_x86_64 -l /dev/null -S -e "$@" diff --git a/misc/nacl/mkzip.go b/misc/nacl/mkzip.go new file mode 100644 index 000000000..7b2de7d47 --- /dev/null +++ b/misc/nacl/mkzip.go @@ -0,0 +1,220 @@ +// Copyright 2014 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. + +// Mkzip creates a zip file from a 'proto' file describing the contents. +// +// The proto file is inspired by the Plan 9 mkfs prototype file format. +// It describes a file tree, one directory per line, with leading tab +// indentation marking the tree structure. Each line contains a leading +// name field giving the name of the file to copy into the zip file, +// and then a sequence of optional key=value attributes to control +// the copy. The only known attribute is src=foo, meaning copy the +// actual data for the file (or directory) from an alternate location. +package main + +import ( + "archive/zip" + "bufio" + "flag" + "fmt" + "io" + "io/ioutil" + "log" + "os" + "path" + "path/filepath" + "strings" +) + +func usage() { + fmt.Fprintf(os.Stderr, "usage: mkzip [-r root] src.proto out.zip\n") + os.Exit(2) +} + +func sysfatal(format string, args ...interface{}) { + fmt.Fprintf(os.Stderr, "mkzip: %s\n", fmt.Sprintf(format, args...)) + os.Exit(2) +} + +var ( + root = flag.String("r", ".", "interpret source paths relative to this directory") + gopackage = flag.String("p", "", "write Go source file in this package") +) + +type stack struct { + name string + src string + depth int +} + +func main() { + log.SetFlags(0) + flag.Usage = usage + flag.Parse() + + args := flag.Args() + if len(args) != 2 { + usage() + } + + rf, err := os.Open(args[0]) + if err != nil { + sysfatal("%v", err) + } + r := bufio.NewScanner(rf) + + zf, err := os.Create(args[1]) + if err != nil { + sysfatal("%v", err) + } + + var w io.Writer = zf + if *gopackage != "" { + fmt.Fprintf(zf, "package %s\n\nfunc init() {\n\tunzip(\"", *gopackage) + gw := &goWriter{b: bufio.NewWriter(w)} + defer func() { + if err := gw.Close(); err != nil { + sysfatal("finishing Go output: %v", err) + } + }() + w = gw + } + z := zip.NewWriter(w) + + lineno := 0 + + addfile := func(info os.FileInfo, dst string, src string) { + zh, err := zip.FileInfoHeader(info) + if err != nil { + sysfatal("%s:%d: %s: %v", args[0], lineno, src, err) + } + zh.Name = dst + zh.Method = zip.Deflate + if info.IsDir() && !strings.HasSuffix(dst, "/") { + zh.Name += "/" + } + w, err := z.CreateHeader(zh) + if err != nil { + sysfatal("%s:%d: %s: %v", args[0], lineno, src, err) + } + if info.IsDir() { + return + } + r, err := os.Open(src) + if err != nil { + sysfatal("%s:%d: %s: %v", args[0], lineno, src, err) + } + defer r.Close() + if _, err := io.Copy(w, r); err != nil { + sysfatal("%s:%d: %s: %v", args[0], lineno, src, err) + } + } + + var stk []stack + + for r.Scan() { + line := r.Text() + lineno++ + s := strings.TrimLeft(line, "\t") + prefix, line := line[:len(line)-len(s)], s + if i := strings.Index(line, "#"); i >= 0 { + line = line[:i] + } + f := strings.Fields(line) + if len(f) == 0 { + continue + } + if strings.HasPrefix(line, " ") { + sysfatal("%s:%d: must use tabs for indentation", args[0], lineno) + } + depth := len(prefix) + for len(stk) > 0 && depth <= stk[len(stk)-1].depth { + stk = stk[:len(stk)-1] + } + parent := "" + psrc := *root + if len(stk) > 0 { + parent = stk[len(stk)-1].name + psrc = stk[len(stk)-1].src + } + if strings.Contains(f[0], "/") { + sysfatal("%s:%d: destination name cannot contain slash", args[0], lineno) + } + name := path.Join(parent, f[0]) + src := filepath.Join(psrc, f[0]) + for _, attr := range f[1:] { + i := strings.Index(attr, "=") + if i < 0 { + sysfatal("%s:%d: malformed attribute %q", args[0], lineno, attr) + } + key, val := attr[:i], attr[i+1:] + switch key { + case "src": + src = val + default: + sysfatal("%s:%d: unknown attribute %q", args[0], lineno, attr) + } + } + + stk = append(stk, stack{name: name, src: src, depth: depth}) + + if f[0] == "*" || f[0] == "+" { + if f[0] == "*" { + dir, err := ioutil.ReadDir(psrc) + if err != nil { + sysfatal("%s:%d: %v", args[0], lineno, err) + } + for _, d := range dir { + addfile(d, path.Join(parent, d.Name()), filepath.Join(psrc, d.Name())) + } + } else { + err := filepath.Walk(psrc, func(src string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if src == psrc { + return nil + } + if psrc == "." { + psrc = "" + } + name := path.Join(parent, filepath.ToSlash(src[len(psrc):])) + addfile(info, name, src) + return nil + }) + if err != nil { + sysfatal("%s:%d: %v", args[0], lineno, err) + } + } + continue + } + + fi, err := os.Stat(src) + if err != nil { + sysfatal("%s:%d: %v", args[0], lineno, err) + } + addfile(fi, name, src) + } + + if err := z.Close(); err != nil { + sysfatal("finishing zip file: %v", err) + } +} + +type goWriter struct { + b *bufio.Writer +} + +func (w *goWriter) Write(b []byte) (int, error) { + for _, c := range b { + fmt.Fprintf(w.b, "\\x%02x", c) + } + return len(b), nil +} + +func (w *goWriter) Close() error { + fmt.Fprintf(w.b, "\")\n}\n") + w.b.Flush() + return nil +} diff --git a/misc/nacl/testdata/bin/placeholder b/misc/nacl/testdata/bin/placeholder new file mode 100644 index 000000000..e69de29bb diff --git a/misc/nacl/testdata/empty b/misc/nacl/testdata/empty new file mode 100644 index 000000000..e69de29bb diff --git a/misc/nacl/testdata/group b/misc/nacl/testdata/group new file mode 100644 index 000000000..eb7f9a307 --- /dev/null +++ b/misc/nacl/testdata/group @@ -0,0 +1,8 @@ +nobody:*:-2: +nogroup:*:-1: +wheel:*:0:root +daemon:*:1:root +kmem:*:2:root +sys:*:3:root +tty:*:4:root +operator:*:5:root diff --git a/misc/nacl/testdata/hosts b/misc/nacl/testdata/hosts new file mode 100644 index 000000000..75721cd5a --- /dev/null +++ b/misc/nacl/testdata/hosts @@ -0,0 +1 @@ +127.0.0.1 localhost diff --git a/misc/nacl/testdata/mime.types b/misc/nacl/testdata/mime.types new file mode 100644 index 000000000..2c41bd2c0 --- /dev/null +++ b/misc/nacl/testdata/mime.types @@ -0,0 +1,1596 @@ +# This file maps Internet media types to unique file extension(s). +# Although created for httpd, this file is used by many software systems +# and has been placed in the public domain for unlimited redisribution. +# +# The table below contains both registered and (common) unregistered types. +# A type that has no unique extension can be ignored -- they are listed +# here to guide configurations toward known types and to make it easier to +# identify "new" types. File extensions are also commonly used to indicate +# content languages and encodings, so choose them carefully. +# +# Internet media types should be registered as described in RFC 4288. +# The registry is at . +# +# MIME type (lowercased) Extensions +# ============================================ ========== +# application/1d-interleaved-parityfec +# application/3gpp-ims+xml +# application/activemessage +application/andrew-inset ez +# application/applefile +application/applixware aw +application/atom+xml atom +application/atomcat+xml atomcat +# application/atomicmail +application/atomsvc+xml atomsvc +# application/auth-policy+xml +# application/batch-smtp +# application/beep+xml +# application/calendar+xml +# application/cals-1840 +# application/ccmp+xml +application/ccxml+xml ccxml +application/cdmi-capability cdmia +application/cdmi-container cdmic +application/cdmi-domain cdmid +application/cdmi-object cdmio +application/cdmi-queue cdmiq +# application/cea-2018+xml +# application/cellml+xml +# application/cfw +# application/cnrp+xml +# application/commonground +# application/conference-info+xml +# application/cpl+xml +# application/csta+xml +# application/cstadata+xml +application/cu-seeme cu +# application/cybercash +application/davmount+xml davmount +# application/dca-rft +# application/dec-dx +# application/dialog-info+xml +# application/dicom +# application/dns +application/docbook+xml dbk +# application/dskpp+xml +application/dssc+der dssc +application/dssc+xml xdssc +# application/dvcs +application/ecmascript ecma +# application/edi-consent +# application/edi-x12 +# application/edifact +application/emma+xml emma +# application/epp+xml +application/epub+zip epub +# application/eshop +# application/example +application/exi exi +# application/fastinfoset +# application/fastsoap +# application/fits +application/font-tdpfr pfr +# application/framework-attributes+xml +application/gml+xml gml +application/gpx+xml gpx +application/gxf gxf +# application/h224 +# application/held+xml +# application/http +application/hyperstudio stk +# application/ibe-key-request+xml +# application/ibe-pkg-reply+xml +# application/ibe-pp-data +# application/iges +# application/im-iscomposing+xml +# application/index +# application/index.cmd +# application/index.obj +# application/index.response +# application/index.vnd +application/inkml+xml ink inkml +# application/iotp +application/ipfix ipfix +# application/ipp +# application/isup +application/java-archive jar +application/java-serialized-object ser +application/java-vm class +application/javascript js +application/json json +application/jsonml+json jsonml +# application/kpml-request+xml +# application/kpml-response+xml +application/lost+xml lostxml +application/mac-binhex40 hqx +application/mac-compactpro cpt +# application/macwriteii +application/mads+xml mads +application/marc mrc +application/marcxml+xml mrcx +application/mathematica ma nb mb +# application/mathml-content+xml +# application/mathml-presentation+xml +application/mathml+xml mathml +# application/mbms-associated-procedure-description+xml +# application/mbms-deregister+xml +# application/mbms-envelope+xml +# application/mbms-msk+xml +# application/mbms-msk-response+xml +# application/mbms-protection-description+xml +# application/mbms-reception-report+xml +# application/mbms-register+xml +# application/mbms-register-response+xml +# application/mbms-user-service-description+xml +application/mbox mbox +# application/media_control+xml +application/mediaservercontrol+xml mscml +application/metalink+xml metalink +application/metalink4+xml meta4 +application/mets+xml mets +# application/mikey +application/mods+xml mods +# application/moss-keys +# application/moss-signature +# application/mosskey-data +# application/mosskey-request +application/mp21 m21 mp21 +application/mp4 mp4s +# application/mpeg4-generic +# application/mpeg4-iod +# application/mpeg4-iod-xmt +# application/msc-ivr+xml +# application/msc-mixer+xml +application/msword doc dot +application/mxf mxf +# application/nasdata +# application/news-checkgroups +# application/news-groupinfo +# application/news-transmission +# application/nss +# application/ocsp-request +# application/ocsp-response +application/octet-stream bin dms lrf mar so dist distz pkg bpk dump elc deploy mobipocket-ebook +application/oda oda +application/oebps-package+xml opf +application/ogg ogx +application/omdoc+xml omdoc +application/onenote onetoc onetoc2 onetmp onepkg +application/oxps oxps +# application/parityfec +application/patch-ops-error+xml xer +application/pdf pdf +application/pgp-encrypted pgp +# application/pgp-keys +application/pgp-signature asc sig +application/pics-rules prf +# application/pidf+xml +# application/pidf-diff+xml +application/pkcs10 p10 +application/pkcs7-mime p7m p7c +application/pkcs7-signature p7s +application/pkcs8 p8 +application/pkix-attr-cert ac +application/pkix-cert cer +application/pkix-crl crl +application/pkix-pkipath pkipath +application/pkixcmp pki +application/pls+xml pls +# application/poc-settings+xml +application/postscript ai eps ps +# application/prs.alvestrand.titrax-sheet +application/prs.cww cww +# application/prs.nprend +# application/prs.plucker +# application/prs.rdf-xml-crypt +# application/prs.xsf+xml +application/pskc+xml pskcxml +# application/qsig +application/rdf+xml rdf +application/reginfo+xml rif +application/relax-ng-compact-syntax rnc +# application/remote-printing +application/resource-lists+xml rl +application/resource-lists-diff+xml rld +# application/riscos +# application/rlmi+xml +application/rls-services+xml rs +application/rpki-ghostbusters gbr +application/rpki-manifest mft +application/rpki-roa roa +# application/rpki-updown +application/rsd+xml rsd +application/rss+xml rss +application/rtf rtf +# application/rtx +# application/samlassertion+xml +# application/samlmetadata+xml +application/sbml+xml sbml +application/scvp-cv-request scq +application/scvp-cv-response scs +application/scvp-vp-request spq +application/scvp-vp-response spp +application/sdp sdp +# application/set-payment +application/set-payment-initiation setpay +# application/set-registration +application/set-registration-initiation setreg +# application/sgml +# application/sgml-open-catalog +application/shf+xml shf +# application/sieve +# application/simple-filter+xml +# application/simple-message-summary +# application/simplesymbolcontainer +# application/slate +# application/smil +application/smil+xml smi smil +# application/soap+fastinfoset +# application/soap+xml +application/sparql-query rq +application/sparql-results+xml srx +# application/spirits-event+xml +application/srgs gram +application/srgs+xml grxml +application/sru+xml sru +application/ssdl+xml ssdl +application/ssml+xml ssml +# application/tamp-apex-update +# application/tamp-apex-update-confirm +# application/tamp-community-update +# application/tamp-community-update-confirm +# application/tamp-error +# application/tamp-sequence-adjust +# application/tamp-sequence-adjust-confirm +# application/tamp-status-query +# application/tamp-status-response +# application/tamp-update +# application/tamp-update-confirm +application/tei+xml tei teicorpus +application/thraud+xml tfi +# application/timestamp-query +# application/timestamp-reply +application/timestamped-data tsd +# application/tve-trigger +# application/ulpfec +# application/vcard+xml +# application/vemmi +# application/vividence.scriptfile +# application/vnd.3gpp.bsf+xml +application/vnd.3gpp.pic-bw-large plb +application/vnd.3gpp.pic-bw-small psb +application/vnd.3gpp.pic-bw-var pvb +# application/vnd.3gpp.sms +# application/vnd.3gpp2.bcmcsinfo+xml +# application/vnd.3gpp2.sms +application/vnd.3gpp2.tcap tcap +application/vnd.3m.post-it-notes pwn +application/vnd.accpac.simply.aso aso +application/vnd.accpac.simply.imp imp +application/vnd.acucobol acu +application/vnd.acucorp atc acutc +application/vnd.adobe.air-application-installer-package+zip air +application/vnd.adobe.formscentral.fcdt fcdt +application/vnd.adobe.fxp fxp fxpl +# application/vnd.adobe.partial-upload +application/vnd.adobe.xdp+xml xdp +application/vnd.adobe.xfdf xfdf +# application/vnd.aether.imp +# application/vnd.ah-barcode +application/vnd.ahead.space ahead +application/vnd.airzip.filesecure.azf azf +application/vnd.airzip.filesecure.azs azs +application/vnd.amazon.ebook azw +application/vnd.americandynamics.acc acc +application/vnd.amiga.ami ami +# application/vnd.amundsen.maze+xml +application/vnd.android.package-archive apk +application/vnd.anser-web-certificate-issue-initiation cii +application/vnd.anser-web-funds-transfer-initiation fti +application/vnd.antix.game-component atx +application/vnd.apple.installer+xml mpkg +application/vnd.apple.mpegurl m3u8 +# application/vnd.arastra.swi +application/vnd.aristanetworks.swi swi +application/vnd.astraea-software.iota iota +application/vnd.audiograph aep +# application/vnd.autopackage +# application/vnd.avistar+xml +application/vnd.blueice.multipass mpm +# application/vnd.bluetooth.ep.oob +application/vnd.bmi bmi +application/vnd.businessobjects rep +# application/vnd.cab-jscript +# application/vnd.canon-cpdl +# application/vnd.canon-lips +# application/vnd.cendio.thinlinc.clientconf +application/vnd.chemdraw+xml cdxml +application/vnd.chipnuts.karaoke-mmd mmd +application/vnd.cinderella cdy +# application/vnd.cirpack.isdn-ext +application/vnd.claymore cla +application/vnd.cloanto.rp9 rp9 +application/vnd.clonk.c4group c4g c4d c4f c4p c4u +application/vnd.cluetrust.cartomobile-config c11amc +application/vnd.cluetrust.cartomobile-config-pkg c11amz +# application/vnd.collection+json +# application/vnd.commerce-battelle +application/vnd.commonspace csp +application/vnd.contact.cmsg cdbcmsg +application/vnd.cosmocaller cmc +application/vnd.crick.clicker clkx +application/vnd.crick.clicker.keyboard clkk +application/vnd.crick.clicker.palette clkp +application/vnd.crick.clicker.template clkt +application/vnd.crick.clicker.wordbank clkw +application/vnd.criticaltools.wbs+xml wbs +application/vnd.ctc-posml pml +# application/vnd.ctct.ws+xml +# application/vnd.cups-pdf +# application/vnd.cups-postscript +application/vnd.cups-ppd ppd +# application/vnd.cups-raster +# application/vnd.cups-raw +# application/vnd.curl +application/vnd.curl.car car +application/vnd.curl.pcurl pcurl +# application/vnd.cybank +application/vnd.dart dart +application/vnd.data-vision.rdz rdz +application/vnd.dece.data uvf uvvf uvd uvvd +application/vnd.dece.ttml+xml uvt uvvt +application/vnd.dece.unspecified uvx uvvx +application/vnd.dece.zip uvz uvvz +application/vnd.denovo.fcselayout-link fe_launch +# application/vnd.dir-bi.plate-dl-nosuffix +application/vnd.dna dna +application/vnd.dolby.mlp mlp +# application/vnd.dolby.mobile.1 +# application/vnd.dolby.mobile.2 +application/vnd.dpgraph dpg +application/vnd.dreamfactory dfac +application/vnd.ds-keypoint kpxx +application/vnd.dvb.ait ait +# application/vnd.dvb.dvbj +# application/vnd.dvb.esgcontainer +# application/vnd.dvb.ipdcdftnotifaccess +# application/vnd.dvb.ipdcesgaccess +# application/vnd.dvb.ipdcesgaccess2 +# application/vnd.dvb.ipdcesgpdd +# application/vnd.dvb.ipdcroaming +# application/vnd.dvb.iptv.alfec-base +# application/vnd.dvb.iptv.alfec-enhancement +# application/vnd.dvb.notif-aggregate-root+xml +# application/vnd.dvb.notif-container+xml +# application/vnd.dvb.notif-generic+xml +# application/vnd.dvb.notif-ia-msglist+xml +# application/vnd.dvb.notif-ia-registration-request+xml +# application/vnd.dvb.notif-ia-registration-response+xml +# application/vnd.dvb.notif-init+xml +# application/vnd.dvb.pfr +application/vnd.dvb.service svc +# application/vnd.dxr +application/vnd.dynageo geo +# application/vnd.easykaraoke.cdgdownload +# application/vnd.ecdis-update +application/vnd.ecowin.chart mag +# application/vnd.ecowin.filerequest +# application/vnd.ecowin.fileupdate +# application/vnd.ecowin.series +# application/vnd.ecowin.seriesrequest +# application/vnd.ecowin.seriesupdate +# application/vnd.emclient.accessrequest+xml +application/vnd.enliven nml +# application/vnd.eprints.data+xml +application/vnd.epson.esf esf +application/vnd.epson.msf msf +application/vnd.epson.quickanime qam +application/vnd.epson.salt slt +application/vnd.epson.ssf ssf +# application/vnd.ericsson.quickcall +application/vnd.eszigno3+xml es3 et3 +# application/vnd.etsi.aoc+xml +# application/vnd.etsi.cug+xml +# application/vnd.etsi.iptvcommand+xml +# application/vnd.etsi.iptvdiscovery+xml +# application/vnd.etsi.iptvprofile+xml +# application/vnd.etsi.iptvsad-bc+xml +# application/vnd.etsi.iptvsad-cod+xml +# application/vnd.etsi.iptvsad-npvr+xml +# application/vnd.etsi.iptvservice+xml +# application/vnd.etsi.iptvsync+xml +# application/vnd.etsi.iptvueprofile+xml +# application/vnd.etsi.mcid+xml +# application/vnd.etsi.overload-control-policy-dataset+xml +# application/vnd.etsi.sci+xml +# application/vnd.etsi.simservs+xml +# application/vnd.etsi.tsl+xml +# application/vnd.etsi.tsl.der +# application/vnd.eudora.data +application/vnd.ezpix-album ez2 +application/vnd.ezpix-package ez3 +# application/vnd.f-secure.mobile +application/vnd.fdf fdf +application/vnd.fdsn.mseed mseed +application/vnd.fdsn.seed seed dataless +# application/vnd.ffsns +# application/vnd.fints +application/vnd.flographit gph +application/vnd.fluxtime.clip ftc +# application/vnd.font-fontforge-sfd +application/vnd.framemaker fm frame maker book +application/vnd.frogans.fnc fnc +application/vnd.frogans.ltf ltf +application/vnd.fsc.weblaunch fsc +application/vnd.fujitsu.oasys oas +application/vnd.fujitsu.oasys2 oa2 +application/vnd.fujitsu.oasys3 oa3 +application/vnd.fujitsu.oasysgp fg5 +application/vnd.fujitsu.oasysprs bh2 +# application/vnd.fujixerox.art-ex +# application/vnd.fujixerox.art4 +# application/vnd.fujixerox.hbpl +application/vnd.fujixerox.ddd ddd +application/vnd.fujixerox.docuworks xdw +application/vnd.fujixerox.docuworks.binder xbd +# application/vnd.fut-misnet +application/vnd.fuzzysheet fzs +application/vnd.genomatix.tuxedo txd +# application/vnd.geocube+xml +application/vnd.geogebra.file ggb +application/vnd.geogebra.tool ggt +application/vnd.geometry-explorer gex gre +application/vnd.geonext gxt +application/vnd.geoplan g2w +application/vnd.geospace g3w +# application/vnd.globalplatform.card-content-mgt +# application/vnd.globalplatform.card-content-mgt-response +application/vnd.gmx gmx +application/vnd.google-earth.kml+xml kml +application/vnd.google-earth.kmz kmz +application/vnd.grafeq gqf gqs +# application/vnd.gridmp +application/vnd.groove-account gac +application/vnd.groove-help ghf +application/vnd.groove-identity-message gim +application/vnd.groove-injector grv +application/vnd.groove-tool-message gtm +application/vnd.groove-tool-template tpl +application/vnd.groove-vcard vcg +# application/vnd.hal+json +application/vnd.hal+xml hal +application/vnd.handheld-entertainment+xml zmm +application/vnd.hbci hbci +# application/vnd.hcl-bireports +application/vnd.hhe.lesson-player les +application/vnd.hp-hpgl hpgl +application/vnd.hp-hpid hpid +application/vnd.hp-hps hps +application/vnd.hp-jlyt jlt +application/vnd.hp-pcl pcl +application/vnd.hp-pclxl pclxl +# application/vnd.httphone +application/vnd.hydrostatix.sof-data sfd-hdstx +# application/vnd.hzn-3d-crossword +# application/vnd.ibm.afplinedata +# application/vnd.ibm.electronic-media +application/vnd.ibm.minipay mpy +application/vnd.ibm.modcap afp listafp list3820 +application/vnd.ibm.rights-management irm +application/vnd.ibm.secure-container sc +application/vnd.iccprofile icc icm +application/vnd.igloader igl +application/vnd.immervision-ivp ivp +application/vnd.immervision-ivu ivu +# application/vnd.informedcontrol.rms+xml +# application/vnd.informix-visionary +# application/vnd.infotech.project +# application/vnd.infotech.project+xml +# application/vnd.innopath.wamp.notification +application/vnd.insors.igm igm +application/vnd.intercon.formnet xpw xpx +application/vnd.intergeo i2g +# application/vnd.intertrust.digibox +# application/vnd.intertrust.nncp +application/vnd.intu.qbo qbo +application/vnd.intu.qfx qfx +# application/vnd.iptc.g2.conceptitem+xml +# application/vnd.iptc.g2.knowledgeitem+xml +# application/vnd.iptc.g2.newsitem+xml +# application/vnd.iptc.g2.newsmessage+xml +# application/vnd.iptc.g2.packageitem+xml +# application/vnd.iptc.g2.planningitem+xml +application/vnd.ipunplugged.rcprofile rcprofile +application/vnd.irepository.package+xml irp +application/vnd.is-xpr xpr +application/vnd.isac.fcs fcs +application/vnd.jam jam +# application/vnd.japannet-directory-service +# application/vnd.japannet-jpnstore-wakeup +# application/vnd.japannet-payment-wakeup +# application/vnd.japannet-registration +# application/vnd.japannet-registration-wakeup +# application/vnd.japannet-setstore-wakeup +# application/vnd.japannet-verification +# application/vnd.japannet-verification-wakeup +application/vnd.jcp.javame.midlet-rms rms +application/vnd.jisp jisp +application/vnd.joost.joda-archive joda +application/vnd.kahootz ktz ktr +application/vnd.kde.karbon karbon +application/vnd.kde.kchart chrt +application/vnd.kde.kformula kfo +application/vnd.kde.kivio flw +application/vnd.kde.kontour kon +application/vnd.kde.kpresenter kpr kpt +application/vnd.kde.kspread ksp +application/vnd.kde.kword kwd kwt +application/vnd.kenameaapp htke +application/vnd.kidspiration kia +application/vnd.kinar kne knp +application/vnd.koan skp skd skt skm +application/vnd.kodak-descriptor sse +application/vnd.las.las+xml lasxml +# application/vnd.liberty-request+xml +application/vnd.llamagraphics.life-balance.desktop lbd +application/vnd.llamagraphics.life-balance.exchange+xml lbe +application/vnd.lotus-1-2-3 123 +application/vnd.lotus-approach apr +application/vnd.lotus-freelance pre +application/vnd.lotus-notes nsf +application/vnd.lotus-organizer org +application/vnd.lotus-screencam scm +application/vnd.lotus-wordpro lwp +application/vnd.macports.portpkg portpkg +# application/vnd.marlin.drm.actiontoken+xml +# application/vnd.marlin.drm.conftoken+xml +# application/vnd.marlin.drm.license+xml +# application/vnd.marlin.drm.mdcf +application/vnd.mcd mcd +application/vnd.medcalcdata mc1 +application/vnd.mediastation.cdkey cdkey +# application/vnd.meridian-slingshot +application/vnd.mfer mwf +application/vnd.mfmp mfm +application/vnd.micrografx.flo flo +application/vnd.micrografx.igx igx +application/vnd.mif mif +# application/vnd.minisoft-hp3000-save +# application/vnd.mitsubishi.misty-guard.trustweb +application/vnd.mobius.daf daf +application/vnd.mobius.dis dis +application/vnd.mobius.mbk mbk +application/vnd.mobius.mqy mqy +application/vnd.mobius.msl msl +application/vnd.mobius.plc plc +application/vnd.mobius.txf txf +application/vnd.mophun.application mpn +application/vnd.mophun.certificate mpc +# application/vnd.motorola.flexsuite +# application/vnd.motorola.flexsuite.adsi +# application/vnd.motorola.flexsuite.fis +# application/vnd.motorola.flexsuite.gotap +# application/vnd.motorola.flexsuite.kmr +# application/vnd.motorola.flexsuite.ttc +# application/vnd.motorola.flexsuite.wem +# application/vnd.motorola.iprm +application/vnd.mozilla.xul+xml xul +application/vnd.ms-artgalry cil +# application/vnd.ms-asf +application/vnd.ms-cab-compressed cab +# application/vnd.ms-color.iccprofile +application/vnd.ms-excel xls xlm xla xlc xlt xlw +application/vnd.ms-excel.addin.macroenabled.12 xlam +application/vnd.ms-excel.sheet.binary.macroenabled.12 xlsb +application/vnd.ms-excel.sheet.macroenabled.12 xlsm +application/vnd.ms-excel.template.macroenabled.12 xltm +application/vnd.ms-fontobject eot +application/vnd.ms-htmlhelp chm +application/vnd.ms-ims ims +application/vnd.ms-lrm lrm +# application/vnd.ms-office.activex+xml +application/vnd.ms-officetheme thmx +# application/vnd.ms-opentype +# application/vnd.ms-package.obfuscated-opentype +application/vnd.ms-pki.seccat cat +application/vnd.ms-pki.stl stl +# application/vnd.ms-playready.initiator+xml +application/vnd.ms-powerpoint ppt pps pot +application/vnd.ms-powerpoint.addin.macroenabled.12 ppam +application/vnd.ms-powerpoint.presentation.macroenabled.12 pptm +application/vnd.ms-powerpoint.slide.macroenabled.12 sldm +application/vnd.ms-powerpoint.slideshow.macroenabled.12 ppsm +application/vnd.ms-powerpoint.template.macroenabled.12 potm +# application/vnd.ms-printing.printticket+xml +application/vnd.ms-project mpp mpt +# application/vnd.ms-tnef +# application/vnd.ms-wmdrm.lic-chlg-req +# application/vnd.ms-wmdrm.lic-resp +# application/vnd.ms-wmdrm.meter-chlg-req +# application/vnd.ms-wmdrm.meter-resp +application/vnd.ms-word.document.macroenabled.12 docm +application/vnd.ms-word.template.macroenabled.12 dotm +application/vnd.ms-works wps wks wcm wdb +application/vnd.ms-wpl wpl +application/vnd.ms-xpsdocument xps +application/vnd.mseq mseq +# application/vnd.msign +# application/vnd.multiad.creator +# application/vnd.multiad.creator.cif +# application/vnd.music-niff +application/vnd.musician mus +application/vnd.muvee.style msty +application/vnd.mynfc taglet +# application/vnd.ncd.control +# application/vnd.ncd.reference +# application/vnd.nervana +# application/vnd.netfpx +application/vnd.neurolanguage.nlu nlu +application/vnd.nitf ntf nitf +application/vnd.noblenet-directory nnd +application/vnd.noblenet-sealer nns +application/vnd.noblenet-web nnw +# application/vnd.nokia.catalogs +# application/vnd.nokia.conml+wbxml +# application/vnd.nokia.conml+xml +# application/vnd.nokia.isds-radio-presets +# application/vnd.nokia.iptv.config+xml +# application/vnd.nokia.landmark+wbxml +# application/vnd.nokia.landmark+xml +# application/vnd.nokia.landmarkcollection+xml +# application/vnd.nokia.n-gage.ac+xml +application/vnd.nokia.n-gage.data ngdat +application/vnd.nokia.n-gage.symbian.install n-gage +# application/vnd.nokia.ncd +# application/vnd.nokia.pcd+wbxml +# application/vnd.nokia.pcd+xml +application/vnd.nokia.radio-preset rpst +application/vnd.nokia.radio-presets rpss +application/vnd.novadigm.edm edm +application/vnd.novadigm.edx edx +application/vnd.novadigm.ext ext +# application/vnd.ntt-local.file-transfer +# application/vnd.ntt-local.sip-ta_remote +# application/vnd.ntt-local.sip-ta_tcp_stream +application/vnd.oasis.opendocument.chart odc +application/vnd.oasis.opendocument.chart-template otc +application/vnd.oasis.opendocument.database odb +application/vnd.oasis.opendocument.formula odf +application/vnd.oasis.opendocument.formula-template odft +application/vnd.oasis.opendocument.graphics odg +application/vnd.oasis.opendocument.graphics-template otg +application/vnd.oasis.opendocument.image odi +application/vnd.oasis.opendocument.image-template oti +application/vnd.oasis.opendocument.presentation odp +application/vnd.oasis.opendocument.presentation-template otp +application/vnd.oasis.opendocument.spreadsheet ods +application/vnd.oasis.opendocument.spreadsheet-template ots +application/vnd.oasis.opendocument.text odt +application/vnd.oasis.opendocument.text-master odm +application/vnd.oasis.opendocument.text-template ott +application/vnd.oasis.opendocument.text-web oth +# application/vnd.obn +# application/vnd.oftn.l10n+json +# application/vnd.oipf.contentaccessdownload+xml +# application/vnd.oipf.contentaccessstreaming+xml +# application/vnd.oipf.cspg-hexbinary +# application/vnd.oipf.dae.svg+xml +# application/vnd.oipf.dae.xhtml+xml +# application/vnd.oipf.mippvcontrolmessage+xml +# application/vnd.oipf.pae.gem +# application/vnd.oipf.spdiscovery+xml +# application/vnd.oipf.spdlist+xml +# application/vnd.oipf.ueprofile+xml +# application/vnd.oipf.userprofile+xml +application/vnd.olpc-sugar xo +# application/vnd.oma-scws-config +# application/vnd.oma-scws-http-request +# application/vnd.oma-scws-http-response +# application/vnd.oma.bcast.associated-procedure-parameter+xml +# application/vnd.oma.bcast.drm-trigger+xml +# application/vnd.oma.bcast.imd+xml +# application/vnd.oma.bcast.ltkm +# application/vnd.oma.bcast.notification+xml +# application/vnd.oma.bcast.provisioningtrigger +# application/vnd.oma.bcast.sgboot +# application/vnd.oma.bcast.sgdd+xml +# application/vnd.oma.bcast.sgdu +# application/vnd.oma.bcast.simple-symbol-container +# application/vnd.oma.bcast.smartcard-trigger+xml +# application/vnd.oma.bcast.sprov+xml +# application/vnd.oma.bcast.stkm +# application/vnd.oma.cab-address-book+xml +# application/vnd.oma.cab-feature-handler+xml +# application/vnd.oma.cab-pcc+xml +# application/vnd.oma.cab-user-prefs+xml +# application/vnd.oma.dcd +# application/vnd.oma.dcdc +application/vnd.oma.dd2+xml dd2 +# application/vnd.oma.drm.risd+xml +# application/vnd.oma.group-usage-list+xml +# application/vnd.oma.pal+xml +# application/vnd.oma.poc.detailed-progress-report+xml +# application/vnd.oma.poc.final-report+xml +# application/vnd.oma.poc.groups+xml +# application/vnd.oma.poc.invocation-descriptor+xml +# application/vnd.oma.poc.optimized-progress-report+xml +# application/vnd.oma.push +# application/vnd.oma.scidm.messages+xml +# application/vnd.oma.xcap-directory+xml +# application/vnd.omads-email+xml +# application/vnd.omads-file+xml +# application/vnd.omads-folder+xml +# application/vnd.omaloc-supl-init +application/vnd.openofficeorg.extension oxt +# application/vnd.openxmlformats-officedocument.custom-properties+xml +# application/vnd.openxmlformats-officedocument.customxmlproperties+xml +# application/vnd.openxmlformats-officedocument.drawing+xml +# application/vnd.openxmlformats-officedocument.drawingml.chart+xml +# application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml +# application/vnd.openxmlformats-officedocument.drawingml.diagramcolors+xml +# application/vnd.openxmlformats-officedocument.drawingml.diagramdata+xml +# application/vnd.openxmlformats-officedocument.drawingml.diagramlayout+xml +# application/vnd.openxmlformats-officedocument.drawingml.diagramstyle+xml +# application/vnd.openxmlformats-officedocument.extended-properties+xml +# application/vnd.openxmlformats-officedocument.presentationml.commentauthors+xml +# application/vnd.openxmlformats-officedocument.presentationml.comments+xml +# application/vnd.openxmlformats-officedocument.presentationml.handoutmaster+xml +# application/vnd.openxmlformats-officedocument.presentationml.notesmaster+xml +# application/vnd.openxmlformats-officedocument.presentationml.notesslide+xml +application/vnd.openxmlformats-officedocument.presentationml.presentation pptx +# application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml +# application/vnd.openxmlformats-officedocument.presentationml.presprops+xml +application/vnd.openxmlformats-officedocument.presentationml.slide sldx +# application/vnd.openxmlformats-officedocument.presentationml.slide+xml +# application/vnd.openxmlformats-officedocument.presentationml.slidelayout+xml +# application/vnd.openxmlformats-officedocument.presentationml.slidemaster+xml +application/vnd.openxmlformats-officedocument.presentationml.slideshow ppsx +# application/vnd.openxmlformats-officedocument.presentationml.slideshow.main+xml +# application/vnd.openxmlformats-officedocument.presentationml.slideupdateinfo+xml +# application/vnd.openxmlformats-officedocument.presentationml.tablestyles+xml +# application/vnd.openxmlformats-officedocument.presentationml.tags+xml +application/vnd.openxmlformats-officedocument.presentationml.template potx +# application/vnd.openxmlformats-officedocument.presentationml.template.main+xml +# application/vnd.openxmlformats-officedocument.presentationml.viewprops+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.calcchain+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.externallink+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcachedefinition+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcacherecords+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.pivottable+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.querytable+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.revisionheaders+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.revisionlog+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.sharedstrings+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx +# application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.sheetmetadata+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.tablesinglecells+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.template xltx +# application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.usernames+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.volatiledependencies+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml +# application/vnd.openxmlformats-officedocument.theme+xml +# application/vnd.openxmlformats-officedocument.themeoverride+xml +# application/vnd.openxmlformats-officedocument.vmldrawing +# application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml +application/vnd.openxmlformats-officedocument.wordprocessingml.document docx +# application/vnd.openxmlformats-officedocument.wordprocessingml.document.glossary+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.fonttable+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml +application/vnd.openxmlformats-officedocument.wordprocessingml.template dotx +# application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.websettings+xml +# application/vnd.openxmlformats-package.core-properties+xml +# application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml +# application/vnd.openxmlformats-package.relationships+xml +# application/vnd.quobject-quoxdocument +# application/vnd.osa.netdeploy +application/vnd.osgeo.mapguide.package mgp +# application/vnd.osgi.bundle +application/vnd.osgi.dp dp +application/vnd.osgi.subsystem esa +# application/vnd.otps.ct-kip+xml +application/vnd.palm pdb pqa oprc +# application/vnd.paos.xml +application/vnd.pawaafile paw +application/vnd.pg.format str +application/vnd.pg.osasli ei6 +# application/vnd.piaccess.application-licence +application/vnd.picsel efif +application/vnd.pmi.widget wg +# application/vnd.poc.group-advertisement+xml +application/vnd.pocketlearn plf +application/vnd.powerbuilder6 pbd +# application/vnd.powerbuilder6-s +# application/vnd.powerbuilder7 +# application/vnd.powerbuilder7-s +# application/vnd.powerbuilder75 +# application/vnd.powerbuilder75-s +# application/vnd.preminet +application/vnd.previewsystems.box box +application/vnd.proteus.magazine mgz +application/vnd.publishare-delta-tree qps +application/vnd.pvi.ptid1 ptid +# application/vnd.pwg-multiplexed +# application/vnd.pwg-xhtml-print+xml +# application/vnd.qualcomm.brew-app-res +application/vnd.quark.quarkxpress qxd qxt qwd qwt qxl qxb +# application/vnd.radisys.moml+xml +# application/vnd.radisys.msml+xml +# application/vnd.radisys.msml-audit+xml +# application/vnd.radisys.msml-audit-conf+xml +# application/vnd.radisys.msml-audit-conn+xml +# application/vnd.radisys.msml-audit-dialog+xml +# application/vnd.radisys.msml-audit-stream+xml +# application/vnd.radisys.msml-conf+xml +# application/vnd.radisys.msml-dialog+xml +# application/vnd.radisys.msml-dialog-base+xml +# application/vnd.radisys.msml-dialog-fax-detect+xml +# application/vnd.radisys.msml-dialog-fax-sendrecv+xml +# application/vnd.radisys.msml-dialog-group+xml +# application/vnd.radisys.msml-dialog-speech+xml +# application/vnd.radisys.msml-dialog-transform+xml +# application/vnd.rainstor.data +# application/vnd.rapid +application/vnd.realvnc.bed bed +application/vnd.recordare.musicxml mxl +application/vnd.recordare.musicxml+xml musicxml +# application/vnd.renlearn.rlprint +application/vnd.rig.cryptonote cryptonote +application/vnd.rim.cod cod +application/vnd.rn-realmedia rm +application/vnd.rn-realmedia-vbr rmvb +application/vnd.route66.link66+xml link66 +# application/vnd.rs-274x +# application/vnd.ruckus.download +# application/vnd.s3sms +application/vnd.sailingtracker.track st +# application/vnd.sbm.cid +# application/vnd.sbm.mid2 +# application/vnd.scribus +# application/vnd.sealed.3df +# application/vnd.sealed.csf +# application/vnd.sealed.doc +# application/vnd.sealed.eml +# application/vnd.sealed.mht +# application/vnd.sealed.net +# application/vnd.sealed.ppt +# application/vnd.sealed.tiff +# application/vnd.sealed.xls +# application/vnd.sealedmedia.softseal.html +# application/vnd.sealedmedia.softseal.pdf +application/vnd.seemail see +application/vnd.sema sema +application/vnd.semd semd +application/vnd.semf semf +application/vnd.shana.informed.formdata ifm +application/vnd.shana.informed.formtemplate itp +application/vnd.shana.informed.interchange iif +application/vnd.shana.informed.package ipk +application/vnd.simtech-mindmapper twd twds +application/vnd.smaf mmf +# application/vnd.smart.notebook +application/vnd.smart.teacher teacher +# application/vnd.software602.filler.form+xml +# application/vnd.software602.filler.form-xml-zip +application/vnd.solent.sdkm+xml sdkm sdkd +application/vnd.spotfire.dxp dxp +application/vnd.spotfire.sfs sfs +# application/vnd.sss-cod +# application/vnd.sss-dtf +# application/vnd.sss-ntf +application/vnd.stardivision.calc sdc +application/vnd.stardivision.draw sda +application/vnd.stardivision.impress sdd +application/vnd.stardivision.math smf +application/vnd.stardivision.writer sdw vor +application/vnd.stardivision.writer-global sgl +application/vnd.stepmania.package smzip +application/vnd.stepmania.stepchart sm +# application/vnd.street-stream +application/vnd.sun.xml.calc sxc +application/vnd.sun.xml.calc.template stc +application/vnd.sun.xml.draw sxd +application/vnd.sun.xml.draw.template std +application/vnd.sun.xml.impress sxi +application/vnd.sun.xml.impress.template sti +application/vnd.sun.xml.math sxm +application/vnd.sun.xml.writer sxw +application/vnd.sun.xml.writer.global sxg +application/vnd.sun.xml.writer.template stw +# application/vnd.sun.wadl+xml +application/vnd.sus-calendar sus susp +application/vnd.svd svd +# application/vnd.swiftview-ics +application/vnd.symbian.install sis sisx +application/vnd.syncml+xml xsm +application/vnd.syncml.dm+wbxml bdm +application/vnd.syncml.dm+xml xdm +# application/vnd.syncml.dm.notification +# application/vnd.syncml.ds.notification +application/vnd.tao.intent-module-archive tao +application/vnd.tcpdump.pcap pcap cap dmp +application/vnd.tmobile-livetv tmo +application/vnd.trid.tpt tpt +application/vnd.triscape.mxs mxs +application/vnd.trueapp tra +# application/vnd.truedoc +# application/vnd.ubisoft.webplayer +application/vnd.ufdl ufd ufdl +application/vnd.uiq.theme utz +application/vnd.umajin umj +application/vnd.unity unityweb +application/vnd.uoml+xml uoml +# application/vnd.uplanet.alert +# application/vnd.uplanet.alert-wbxml +# application/vnd.uplanet.bearer-choice +# application/vnd.uplanet.bearer-choice-wbxml +# application/vnd.uplanet.cacheop +# application/vnd.uplanet.cacheop-wbxml +# application/vnd.uplanet.channel +# application/vnd.uplanet.channel-wbxml +# application/vnd.uplanet.list +# application/vnd.uplanet.list-wbxml +# application/vnd.uplanet.listcmd +# application/vnd.uplanet.listcmd-wbxml +# application/vnd.uplanet.signal +application/vnd.vcx vcx +# application/vnd.vd-study +# application/vnd.vectorworks +# application/vnd.verimatrix.vcas +# application/vnd.vidsoft.vidconference +application/vnd.visio vsd vst vss vsw +application/vnd.visionary vis +# application/vnd.vividence.scriptfile +application/vnd.vsf vsf +# application/vnd.wap.sic +# application/vnd.wap.slc +application/vnd.wap.wbxml wbxml +application/vnd.wap.wmlc wmlc +application/vnd.wap.wmlscriptc wmlsc +application/vnd.webturbo wtb +# application/vnd.wfa.wsc +# application/vnd.wmc +# application/vnd.wmf.bootstrap +# application/vnd.wolfram.mathematica +# application/vnd.wolfram.mathematica.package +application/vnd.wolfram.player nbp +application/vnd.wordperfect wpd +application/vnd.wqd wqd +# application/vnd.wrq-hp3000-labelled +application/vnd.wt.stf stf +# application/vnd.wv.csp+wbxml +# application/vnd.wv.csp+xml +# application/vnd.wv.ssp+xml +application/vnd.xara xar +application/vnd.xfdl xfdl +# application/vnd.xfdl.webform +# application/vnd.xmi+xml +# application/vnd.xmpie.cpkg +# application/vnd.xmpie.dpkg +# application/vnd.xmpie.plan +# application/vnd.xmpie.ppkg +# application/vnd.xmpie.xlim +application/vnd.yamaha.hv-dic hvd +application/vnd.yamaha.hv-script hvs +application/vnd.yamaha.hv-voice hvp +application/vnd.yamaha.openscoreformat osf +application/vnd.yamaha.openscoreformat.osfpvg+xml osfpvg +# application/vnd.yamaha.remote-setup +application/vnd.yamaha.smaf-audio saf +application/vnd.yamaha.smaf-phrase spf +# application/vnd.yamaha.through-ngn +# application/vnd.yamaha.tunnel-udpencap +application/vnd.yellowriver-custom-menu cmp +application/vnd.zul zir zirz +application/vnd.zzazz.deck+xml zaz +application/voicexml+xml vxml +# application/vq-rtcpxr +# application/watcherinfo+xml +# application/whoispp-query +# application/whoispp-response +application/widget wgt +application/winhlp hlp +# application/wita +# application/wordperfect5.1 +application/wsdl+xml wsdl +application/wspolicy+xml wspolicy +application/x-7z-compressed 7z +application/x-abiword abw +application/x-ace-compressed ace +# application/x-amf +application/x-apple-diskimage dmg +application/x-authorware-bin aab x32 u32 vox +application/x-authorware-map aam +application/x-authorware-seg aas +application/x-bcpio bcpio +application/x-bittorrent torrent +application/x-blorb blb blorb +application/x-bzip bz +application/x-bzip2 bz2 boz +application/x-cbr cbr cba cbt cbz cb7 +application/x-cdlink vcd +application/x-cfs-compressed cfs +application/x-chat chat +application/x-chess-pgn pgn +application/x-conference nsc +# application/x-compress +application/x-cpio cpio +application/x-csh csh +application/x-debian-package deb udeb +application/x-dgc-compressed dgc +application/x-director dir dcr dxr cst cct cxt w3d fgd swa +application/x-doom wad +application/x-dtbncx+xml ncx +application/x-dtbook+xml dtb +application/x-dtbresource+xml res +application/x-dvi dvi +application/x-envoy evy +application/x-eva eva +application/x-font-bdf bdf +# application/x-font-dos +# application/x-font-framemaker +application/x-font-ghostscript gsf +# application/x-font-libgrx +application/x-font-linux-psf psf +application/x-font-otf otf +application/x-font-pcf pcf +application/x-font-snf snf +# application/x-font-speedo +# application/x-font-sunos-news +application/x-font-ttf ttf ttc +application/x-font-type1 pfa pfb pfm afm +application/x-font-woff woff +# application/x-font-vfont +application/x-freearc arc +application/x-futuresplash spl +application/x-gca-compressed gca +application/x-glulx ulx +application/x-gnumeric gnumeric +application/x-gramps-xml gramps +application/x-gtar gtar +# application/x-gzip +application/x-hdf hdf +application/x-install-instructions install +application/x-iso9660-image iso +application/x-java-jnlp-file jnlp +application/x-latex latex +application/x-lzh-compressed lzh lha +application/x-mie mie +application/x-mobipocket-ebook prc mobi +application/x-mpegurl m3u8 +application/x-ms-application application +application/x-ms-shortcut lnk +application/x-ms-wmd wmd +application/x-ms-wmz wmz +application/x-ms-xbap xbap +application/x-msaccess mdb +application/x-msbinder obd +application/x-mscardfile crd +application/x-msclip clp +application/x-msdownload exe dll com bat msi +application/x-msmediaview mvb m13 m14 +application/x-msmetafile wmf wmz emf emz +application/x-msmoney mny +application/x-mspublisher pub +application/x-msschedule scd +application/x-msterminal trm +application/x-mswrite wri +application/x-netcdf nc cdf +application/x-nzb nzb +application/x-pkcs12 p12 pfx +application/x-pkcs7-certificates p7b spc +application/x-pkcs7-certreqresp p7r +application/x-rar-compressed rar +application/x-research-info-systems ris +application/x-sh sh +application/x-shar shar +application/x-shockwave-flash swf +application/x-silverlight-app xap +application/x-sql sql +application/x-stuffit sit +application/x-stuffitx sitx +application/x-subrip srt +application/x-sv4cpio sv4cpio +application/x-sv4crc sv4crc +application/x-t3vm-image t3 +application/x-tads gam +application/x-tar tar +application/x-tcl tcl +application/x-tex tex +application/x-tex-tfm tfm +application/x-texinfo texinfo texi +application/x-tgif obj +application/x-ustar ustar +application/x-wais-source src +application/x-x509-ca-cert der crt +application/x-xfig fig +application/x-xliff+xml xlf +application/x-xpinstall xpi +application/x-xz xz +application/x-zmachine z1 z2 z3 z4 z5 z6 z7 z8 +# application/x400-bp +application/xaml+xml xaml +# application/xcap-att+xml +# application/xcap-caps+xml +application/xcap-diff+xml xdf +# application/xcap-el+xml +# application/xcap-error+xml +# application/xcap-ns+xml +# application/xcon-conference-info-diff+xml +# application/xcon-conference-info+xml +application/xenc+xml xenc +application/xhtml+xml xhtml xht +# application/xhtml-voice+xml +application/xml xml xsl +application/xml-dtd dtd +# application/xml-external-parsed-entity +# application/xmpp+xml +application/xop+xml xop +application/xproc+xml xpl +application/xslt+xml xslt +application/xspf+xml xspf +application/xv+xml mxml xhvml xvml xvm +application/yang yang +application/yin+xml yin +application/zip zip +# audio/1d-interleaved-parityfec +# audio/32kadpcm +# audio/3gpp +# audio/3gpp2 +# audio/ac3 +audio/adpcm adp +# audio/amr +# audio/amr-wb +# audio/amr-wb+ +# audio/asc +# audio/atrac-advanced-lossless +# audio/atrac-x +# audio/atrac3 +audio/basic au snd +# audio/bv16 +# audio/bv32 +# audio/clearmode +# audio/cn +# audio/dat12 +# audio/dls +# audio/dsr-es201108 +# audio/dsr-es202050 +# audio/dsr-es202211 +# audio/dsr-es202212 +# audio/dv +# audio/dvi4 +# audio/eac3 +# audio/evrc +# audio/evrc-qcp +# audio/evrc0 +# audio/evrc1 +# audio/evrcb +# audio/evrcb0 +# audio/evrcb1 +# audio/evrcwb +# audio/evrcwb0 +# audio/evrcwb1 +# audio/example +# audio/fwdred +# audio/g719 +# audio/g722 +# audio/g7221 +# audio/g723 +# audio/g726-16 +# audio/g726-24 +# audio/g726-32 +# audio/g726-40 +# audio/g728 +# audio/g729 +# audio/g7291 +# audio/g729d +# audio/g729e +# audio/gsm +# audio/gsm-efr +# audio/gsm-hr-08 +# audio/ilbc +# audio/ip-mr_v2.5 +# audio/isac +# audio/l16 +# audio/l20 +# audio/l24 +# audio/l8 +# audio/lpc +audio/midi mid midi kar rmi +# audio/mobile-xmf +audio/mp4 mp4a +# audio/mp4a-latm +audio/mp4a-latm m4a m4p +# audio/mpa +# audio/mpa-robust +audio/mpeg mpga mp2 mp2a mp3 m2a m3a +# audio/mpeg4-generic +# audio/musepack +audio/ogg oga ogg spx +# audio/opus +# audio/parityfec +# audio/pcma +# audio/pcma-wb +# audio/pcmu-wb +# audio/pcmu +# audio/prs.sid +# audio/qcelp +# audio/red +# audio/rtp-enc-aescm128 +# audio/rtp-midi +# audio/rtx +audio/s3m s3m +audio/silk sil +# audio/smv +# audio/smv0 +# audio/smv-qcp +# audio/sp-midi +# audio/speex +# audio/t140c +# audio/t38 +# audio/telephone-event +# audio/tone +# audio/uemclip +# audio/ulpfec +# audio/vdvi +# audio/vmr-wb +# audio/vnd.3gpp.iufp +# audio/vnd.4sb +# audio/vnd.audiokoz +# audio/vnd.celp +# audio/vnd.cisco.nse +# audio/vnd.cmles.radio-events +# audio/vnd.cns.anp1 +# audio/vnd.cns.inf1 +audio/vnd.dece.audio uva uvva +audio/vnd.digital-winds eol +# audio/vnd.dlna.adts +# audio/vnd.dolby.heaac.1 +# audio/vnd.dolby.heaac.2 +# audio/vnd.dolby.mlp +# audio/vnd.dolby.mps +# audio/vnd.dolby.pl2 +# audio/vnd.dolby.pl2x +# audio/vnd.dolby.pl2z +# audio/vnd.dolby.pulse.1 +audio/vnd.dra dra +audio/vnd.dts dts +audio/vnd.dts.hd dtshd +# audio/vnd.dvb.file +# audio/vnd.everad.plj +# audio/vnd.hns.audio +audio/vnd.lucent.voice lvp +audio/vnd.ms-playready.media.pya pya +# audio/vnd.nokia.mobile-xmf +# audio/vnd.nortel.vbk +audio/vnd.nuera.ecelp4800 ecelp4800 +audio/vnd.nuera.ecelp7470 ecelp7470 +audio/vnd.nuera.ecelp9600 ecelp9600 +# audio/vnd.octel.sbc +# audio/vnd.qcelp +# audio/vnd.rhetorex.32kadpcm +audio/vnd.rip rip +# audio/vnd.sealedmedia.softseal.mpeg +# audio/vnd.vmx.cvsd +# audio/vorbis +# audio/vorbis-config +audio/webm weba +audio/x-aac aac +audio/x-aiff aif aiff aifc +audio/x-caf caf +audio/x-flac flac +audio/x-matroska mka +audio/x-mpegurl m3u +audio/x-ms-wax wax +audio/x-ms-wma wma +audio/x-pn-realaudio ram ra +audio/x-pn-realaudio-plugin rmp +# audio/x-tta +audio/x-wav wav +audio/xm xm +chemical/x-cdx cdx +chemical/x-cif cif +chemical/x-cmdf cmdf +chemical/x-cml cml +chemical/x-csml csml +# chemical/x-pdb +chemical/x-xyz xyz +image/bmp bmp +image/cgm cgm +# image/example +# image/fits +image/g3fax g3 +image/gif gif +image/ief ief +# image/jp2 +image/jp2 jp2 +image/jpeg jpeg jpg jpe +# image/jpm +# image/jpx +image/ktx ktx +# image/naplps +image/pict pict pic pct +image/png png +image/prs.btif btif +# image/prs.pti +image/sgi sgi +image/svg+xml svg svgz +# image/t38 +image/tiff tiff tif +# image/tiff-fx +image/vnd.adobe.photoshop psd +# image/vnd.cns.inf2 +image/vnd.dece.graphic uvi uvvi uvg uvvg +image/vnd.dvb.subtitle sub +image/vnd.djvu djvu djv +image/vnd.dwg dwg +image/vnd.dxf dxf +image/vnd.fastbidsheet fbs +image/vnd.fpx fpx +image/vnd.fst fst +image/vnd.fujixerox.edmics-mmr mmr +image/vnd.fujixerox.edmics-rlc rlc +# image/vnd.globalgraphics.pgb +# image/vnd.microsoft.icon +# image/vnd.mix +image/vnd.ms-modi mdi +image/vnd.ms-photo wdp +image/vnd.net-fpx npx +# image/vnd.radiance +# image/vnd.sealed.png +# image/vnd.sealedmedia.softseal.gif +# image/vnd.sealedmedia.softseal.jpg +# image/vnd.svf +image/vnd.wap.wbmp wbmp +image/vnd.xiff xif +image/webp webp +image/x-3ds 3ds +image/x-cmu-raster ras +image/x-cmx cmx +image/x-freehand fh fhc fh4 fh5 fh7 +image/x-icon ico +image/x-macpaint pntg pnt mac +image/x-mrsid-image sid +image/x-pcx pcx +image/x-pict pic pct +image/x-portable-anymap pnm +image/x-portable-bitmap pbm +image/x-portable-graymap pgm +image/x-portable-pixmap ppm +image/x-quicktime qtif qti +image/x-rgb rgb +image/x-tga tga +image/x-xbitmap xbm +image/x-xpixmap xpm +image/x-xwindowdump xwd +# message/cpim +# message/delivery-status +# message/disposition-notification +# message/example +# message/external-body +# message/feedback-report +# message/global +# message/global-delivery-status +# message/global-disposition-notification +# message/global-headers +# message/http +# message/imdn+xml +# message/news +# message/partial +message/rfc822 eml mime +# message/s-http +# message/sip +# message/sipfrag +# message/tracking-status +# message/vnd.si.simp +# model/example +model/iges igs iges +model/mesh msh mesh silo +model/vnd.collada+xml dae +model/vnd.dwf dwf +# model/vnd.flatland.3dml +model/vnd.gdl gdl +# model/vnd.gs-gdl +# model/vnd.gs.gdl +model/vnd.gtw gtw +# model/vnd.moml+xml +model/vnd.mts mts +# model/vnd.parasolid.transmit.binary +# model/vnd.parasolid.transmit.text +model/vnd.vtu vtu +model/vrml wrl vrml +model/x3d+binary x3db x3dbz +model/x3d+vrml x3dv x3dvz +model/x3d+xml x3d x3dz +# multipart/alternative +# multipart/appledouble +# multipart/byteranges +# multipart/digest +# multipart/encrypted +# multipart/example +# multipart/form-data +# multipart/header-set +# multipart/mixed +# multipart/parallel +# multipart/related +# multipart/report +# multipart/signed +# multipart/voice-message +text/cache-manifest manifest +# text/1d-interleaved-parityfec +text/cache-manifest appcache +text/calendar ics ifb +text/css css +text/csv csv +# text/directory +# text/dns +# text/ecmascript +# text/enriched +# text/example +# text/fwdred +text/html html htm +# text/javascript +text/n3 n3 +# text/parityfec +text/plain txt text conf def list log in +# text/prs.fallenstein.rst +text/prs.lines.tag dsc +# text/vnd.radisys.msml-basic-layout +# text/red +# text/rfc822-headers +text/richtext rtx +# text/rtf +# text/rtp-enc-aescm128 +# text/rtx +text/sgml sgml sgm +# text/t140 +text/tab-separated-values tsv +text/troff t tr roff man me ms +text/turtle ttl +# text/ulpfec +text/uri-list uri uris urls +text/vcard vcard +# text/vnd.abc +text/vnd.curl curl +text/vnd.curl.dcurl dcurl +text/vnd.curl.scurl scurl +text/vnd.curl.mcurl mcurl +# text/vnd.dmclientscript +text/vnd.dvb.subtitle sub +# text/vnd.esmertec.theme-descriptor +text/vnd.fly fly +text/vnd.fmi.flexstor flx +text/vnd.graphviz gv +text/vnd.in3d.3dml 3dml +text/vnd.in3d.spot spot +# text/vnd.iptc.newsml +# text/vnd.iptc.nitf +# text/vnd.latex-z +# text/vnd.motorola.reflex +# text/vnd.ms-mediapackage +# text/vnd.net2phone.commcenter.command +# text/vnd.si.uricatalogue +text/vnd.sun.j2me.app-descriptor jad +# text/vnd.trolltech.linguist +# text/vnd.wap.si +# text/vnd.wap.sl +text/vnd.wap.wml wml +text/vnd.wap.wmlscript wmls +text/x-asm s asm +text/x-c c cc cxx cpp h hh dic +text/x-fortran f for f77 f90 +text/x-java-source java +text/x-opml opml +text/x-pascal p pas +text/x-nfo nfo +text/x-setext etx +text/x-sfv sfv +text/x-uuencode uu +text/x-vcalendar vcs +text/x-vcard vcf +# text/xml +# text/xml-external-parsed-entity +# video/1d-interleaved-parityfec +video/3gpp 3gp +# video/3gpp-tt +video/3gpp2 3g2 +# video/bmpeg +# video/bt656 +# video/celb +# video/dv +# video/example +video/h261 h261 +video/h263 h263 +# video/h263-1998 +# video/h263-2000 +video/h264 h264 +# video/h264-rcdo +# video/h264-svc +video/jpeg jpgv +# video/jpeg2000 +video/jpm jpm jpgm +video/mj2 mj2 mjp2 +# video/mp1s +# video/mp2p +# video/mp4v-es +video/mp2t ts +video/mp4 mp4 mp4v mpg4 m4v +video/mpeg mpeg mpg mpe m1v m2v +# video/mpeg4-generic +# video/mpv +# video/nv +video/ogg ogv +# video/parityfec +# video/pointer +video/quicktime qt mov +# video/raw +# video/rtp-enc-aescm128 +# video/rtx +# video/smpte292m +# video/ulpfec +# video/vc1 +# video/vnd.cctv +video/vnd.dece.hd uvh uvvh +video/vnd.dece.mobile uvm uvvm +# video/vnd.dece.mp4 +video/vnd.dece.pd uvp uvvp +video/vnd.dece.sd uvs uvvs +video/vnd.dece.video uvv uvvv +# video/vnd.directv.mpeg +# video/vnd.directv.mpeg-tts +# video/vnd.dlna.mpeg-tts +video/vnd.dvb.file dvb +video/vnd.fvt fvt +# video/vnd.hns.video +# video/vnd.iptvforum.1dparityfec-1010 +# video/vnd.iptvforum.1dparityfec-2005 +# video/vnd.iptvforum.2dparityfec-1010 +# video/vnd.iptvforum.2dparityfec-2005 +# video/vnd.iptvforum.ttsavc +# video/vnd.iptvforum.ttsmpeg2 +# video/vnd.motorola.video +# video/vnd.motorola.videop +video/vnd.mpegurl mxu m4u +video/vnd.ms-playready.media.pyv pyv +# video/vnd.nokia.interleaved-multimedia +# video/vnd.nokia.videovoip +# video/vnd.objectvideo +# video/vnd.sealed.mpeg1 +# video/vnd.sealed.mpeg4 +# video/vnd.sealed.swf +# video/vnd.sealedmedia.softseal.mov +video/vnd.uvvu.mp4 uvu uvvu +video/vnd.vivo viv +video/x-dv dv dif +video/webm webm +video/x-f4v f4v +video/x-fli fli +video/x-flv flv +video/x-m4v m4v +video/x-matroska mkv mk3d mks +video/x-mng mng +video/x-ms-asf asf asx +video/x-ms-vob vob +video/x-ms-wm wm +video/x-ms-wmv wmv +video/x-ms-wmx wmx +video/x-ms-wvx wvx +video/x-msvideo avi +video/x-sgi-movie movie +video/x-smv smv +x-conference/x-cooltalk ice diff --git a/misc/nacl/testzip.proto b/misc/nacl/testzip.proto new file mode 100644 index 000000000..2701ff463 --- /dev/null +++ b/misc/nacl/testzip.proto @@ -0,0 +1,113 @@ +etc src=/etc + mime.types src=../misc/nacl/testdata/mime.types + resolv.conf src=../misc/nacl/testdata/empty + group src=../misc/nacl/testdata/group + passwd src=../misc/nacl/testdata/empty + hosts src=../misc/nacl/testdata/hosts + services +usr src=../misc/nacl/testdata + bin +go src=.. + src + cmd + gofmt + testdata + + + pkg + archive + tar + testdata + + + zip + testdata + + + compress + bzip2 + testdata + + + flate + gzip + testdata + + + lzw + testdata + + + zlib + crypto + rsa + testdata + + + tls + testdata + + + debug + dwarf + testdata + + + elf + testdata + + + macho + testdata + + + pe + testdata + + + plan9obj + testdata + + + go + build + + + doc + testdata + + + format + + + parser + + + printer + + + image + testdata + + + draw + gif + jpeg + png + testdata + + + io + + + mime + testdata + + + multipart + testdata + + + net + http + + + testdata + + + os + + + path + filepath + + + regexp + testdata + + + strconv + testdata + + + text + template + testdata + + + lib + time + zoneinfo.zip + + test + + diff --git a/misc/notepadplus/functionList.xml b/misc/notepadplus/functionList.xml index ca949f018..7c605db4f 100644 --- a/misc/notepadplus/functionList.xml +++ b/misc/notepadplus/functionList.xml @@ -1,8 +1,15 @@ + + + diff --git a/misc/pprof b/misc/pprof index 1fc8d3621..ad3f1ebe1 100755 --- a/misc/pprof +++ b/misc/pprof @@ -730,6 +730,13 @@ sub RunWeb { return; } + if (`uname` =~ /CYGWIN/) { + # Windows(cygwin): open will use standard preference for SVG files. + my $winname = `cygpath -wa $fname`; + system("explorer.exe", $winname); + return; + } + # Some kind of Unix; try generic symlinks, then specific browsers. # (Stop once we find one.) # Works best if the browser is already running. @@ -2645,6 +2652,7 @@ sub RemoveUninterestingFrames { 'makechan', 'makemap', 'mal', + 'profilealloc', 'runtime.new', 'makeslice1', 'runtime.malloc', @@ -4608,6 +4616,7 @@ sub ConfigureObjTools { # in the same directory as pprof. $obj_tool_map{"nm_pdb"} = "nm-pdb"; $obj_tool_map{"addr2line_pdb"} = "addr2line-pdb"; + $obj_tool_map{"objdump"} = "false"; # no objdump } if ($file_type =~ /Mach-O/) { diff --git a/misc/vim/autoload/go/complete.vim b/misc/vim/autoload/go/complete.vim index 8dd43de4a..a4fa6b668 100644 --- a/misc/vim/autoload/go/complete.vim +++ b/misc/vim/autoload/go/complete.vim @@ -58,7 +58,7 @@ function! go#complete#Package(ArgLead, CmdLine, CursorPos) if executable('go') let goroot = substitute(system('go env GOROOT'), '\n', '', 'g') if v:shell_error - echomsg '\'go env GOROOT\' failed' + echomsg '''go env GOROOT'' failed' endif else let goroot = $GOROOT diff --git a/misc/vim/ftplugin/go.vim b/misc/vim/ftplugin/go.vim index 8066733cf..532fb1723 100644 --- a/misc/vim/ftplugin/go.vim +++ b/misc/vim/ftplugin/go.vim @@ -9,9 +9,11 @@ if exists("b:did_ftplugin") endif let b:did_ftplugin = 1 +setlocal formatoptions-=t + setlocal comments=s1:/*,mb:*,ex:*/,:// setlocal commentstring=//\ %s -let b:undo_ftplugin = "setl com< cms<" +let b:undo_ftplugin = "setl fo< com< cms<" " vim:ts=4:sw=4:et diff --git a/misc/vim/ftplugin/go/fmt.vim b/misc/vim/ftplugin/go/fmt.vim index 5f7976f5f..359545bd4 100644 --- a/misc/vim/ftplugin/go/fmt.vim +++ b/misc/vim/ftplugin/go/fmt.vim @@ -57,7 +57,7 @@ function! s:GoFormat() endif undo if !empty(errors) - call setloclist(0, errors, 'r') + call setqflist(errors, 'r') endif echohl Error | echomsg "Gofmt returned error" | echohl None endif diff --git a/misc/vim/indent/go.vim b/misc/vim/indent/go.vim index faf4d79e2..e3d6e8416 100644 --- a/misc/vim/indent/go.vim +++ b/misc/vim/indent/go.vim @@ -24,6 +24,18 @@ if exists("*GoIndent") finish endif +" The shiftwidth() function is relatively new. +" Don't require it to exist. +if exists('*shiftwidth') + func s:sw() + return shiftwidth() + endfunc +else + func s:sw() + return &shiftwidth + endfunc +endif + function! GoIndent(lnum) let prevlnum = prevnonblank(a:lnum-1) if prevlnum == 0 @@ -40,17 +52,17 @@ function! GoIndent(lnum) if prevl =~ '[({]\s*$' " previous line opened a block - let ind += &sw + let ind += s:sw() endif if prevl =~# '^\s*\(case .*\|default\):$' " previous line is part of a switch statement - let ind += &sw + let ind += s:sw() endif " TODO: handle if the previous line is a label. if thisl =~ '^\s*[)}]' " this line closed a block - let ind -= &sw + let ind -= s:sw() endif " Colons are tricky. @@ -58,7 +70,7 @@ function! GoIndent(lnum) " We ignore trying to deal with jump labels because (a) they're rare, and " (b) they're hard to disambiguate from a composite literal key. if thisl =~# '^\s*\(case .*\|default\):$' - let ind -= &sw + let ind -= s:sw() endif return ind diff --git a/misc/vim/readme.txt b/misc/vim/readme.txt index b8469f927..9a9e22870 100644 --- a/misc/vim/readme.txt +++ b/misc/vim/readme.txt @@ -5,9 +5,11 @@ To use all the Vim plugins, add these lines to your $HOME/.vimrc. " Some Linux distributions set filetype in /etc/vimrc. " Clear filetype flags before changing runtimepath to force Vim to reload them. - filetype off - filetype plugin indent off - set runtimepath+=$GOROOT/misc/vim + if exists("g:did_load_filetypes") + filetype off + filetype plugin indent off + endif + set runtimepath+=$GOROOT/misc/vim " replace $GOROOT with the output of: go env GOROOT filetype plugin indent on syntax on diff --git a/misc/zsh/go b/misc/zsh/go index 18bcaaff2..066cf4065 100644 --- a/misc/zsh/go +++ b/misc/zsh/go @@ -19,7 +19,6 @@ __go_tool_complete() { commands+=( 'build[compile packages and dependencies]' 'clean[remove object files]' - 'doc[run godoc on package sources]' 'env[print Go environment information]' 'fix[run go tool fix on packages]' 'fmt[run gofmt on package sources]' @@ -92,6 +91,7 @@ __go_tool_complete() { "-short[use short mode]" \ "-parallel[number of parallel tests]:number" \ "-cpu[values of GOMAXPROCS to use]:number list" \ + "-cover[enable coverage analysis]" \ "-run[run tests and examples matching regexp]:regexp" \ "-bench[run benchmarks matching regexp]:regexp" \ "-benchmem[print memory allocation stats]" \ @@ -106,9 +106,10 @@ __go_tool_complete() { ;; help) _values "${commands[@]}" \ + 'c[how to call C code]' \ + 'importpath[description of import path]' \ 'gopath[GOPATH environment variable]' \ 'packages[description of package lists]' \ - 'remote[remote import path syntax]' \ 'testflag[description of testing flags]' \ 'testfunc[description of testing functions]' ;; diff --git a/src/all.bash b/src/all.bash index 488ca4679..5d994d3d0 100755 --- a/src/all.bash +++ b/src/all.bash @@ -9,7 +9,7 @@ if [ ! -f make.bash ]; then exit 1 fi OLDPATH="$PATH" -. ./make.bash --no-banner +. ./make.bash "$@" --no-banner bash run.bash --no-rebuild PATH="$OLDPATH" $GOTOOLDIR/dist banner # print build info diff --git a/src/cmd/5a/a.h b/src/cmd/5a/a.h index 8b39d610f..bb60fe7de 100644 --- a/src/cmd/5a/a.h +++ b/src/cmd/5a/a.h @@ -29,6 +29,7 @@ // THE SOFTWARE. #include +#include #include "../5l/5.out.h" #ifndef EXTERN @@ -43,9 +44,7 @@ #define ungetc ccungetc typedef struct Sym Sym; -typedef struct Gen Gen; typedef struct Io Io; -typedef struct Hist Hist; #define MAXALIGN 7 #define FPCHIP 1 @@ -88,33 +87,6 @@ struct Io }; #define I ((Io*)0) -EXTERN struct -{ - Sym* sym; - short type; -} h[NSYM]; - -struct Gen -{ - Sym* sym; - int32 offset; - int32 offset2; - short type; - short reg; - short name; - double dval; - char sval[8]; -}; - -struct Hist -{ - Hist* link; - char* name; - int32 line; - int32 offset; -}; -#define H ((Hist*)0) - enum { CLAST, @@ -125,13 +97,11 @@ enum Always = 14, }; -EXTERN char debug[256]; +EXTERN int debug[256]; EXTERN Sym* hash[NHASH]; EXTERN char** Dlist; EXTERN int nDlist; -EXTERN Hist* ehist; EXTERN int newflag; -EXTERN Hist* hist; EXTERN char* hunk; EXTERN char** include; EXTERN Io* iofree; @@ -142,10 +112,9 @@ EXTERN int nerrors; EXTERN int32 nhunk; EXTERN int ninclude; EXTERN int32 nsymb; -EXTERN Gen nullgen; +EXTERN Addr nullgen; EXTERN char* outfile; EXTERN int pass; -EXTERN char* pathname; EXTERN int32 pc; EXTERN int peekc; EXTERN int32 stmtline; @@ -155,6 +124,8 @@ EXTERN int thechar; EXTERN char* thestring; EXTERN int32 thunk; EXTERN Biobuf obuf; +EXTERN Link* ctxt; +EXTERN Biobuf bstdout; void* alloc(int32); void* allocn(void*, int32, int32); @@ -174,11 +145,8 @@ int escchar(int); void cinit(void); void pinit(char*); void cclean(void); -int isreg(Gen*); -void outcode(int, int, Gen*, int, Gen*); -void zname(char*, int, int); -void zaddr(Gen*, int); -void ieeedtod(Ieee*, double); +int isreg(Addr*); +void outcode(int, int, Addr*, int, Addr*); int filbuf(void); Sym* getsym(void); void domacro(void); @@ -190,7 +158,6 @@ void maclin(void); void macprag(void); void macif(int); void macend(void); -void outhist(void); void dodefine(char*); void prfile(int32); void linehist(char*, int); @@ -199,3 +166,4 @@ void yyerror(char*, ...); int yyparse(void); void setinclude(char*); int assemble(char*); +void listinit(void); diff --git a/src/cmd/5a/a.y b/src/cmd/5a/a.y index c506ff9d5..56d0c563d 100644 --- a/src/cmd/5a/a.y +++ b/src/cmd/5a/a.y @@ -41,7 +41,7 @@ int32 lval; double dval; char sval[8]; - Gen gen; + Addr addr; } %left '|' %left '^' @@ -62,8 +62,8 @@ %token LNAME LLAB LVAR %type con expr oexpr pointer offset sreg spreg creg %type rcon cond reglist -%type gen rel reg regreg freg shift fcon frcon -%type imm ximm name oreg ireg nireg ioreg imsr +%type gen rel reg regreg freg shift fcon frcon +%type imm ximm name oreg ireg nireg ioreg imsr %% prog: | prog @@ -175,7 +175,7 @@ inst: */ | LTYPE8 cond ioreg ',' '[' reglist ']' { - Gen g; + Addr g; g = nullgen; g.type = D_CONST; @@ -184,7 +184,7 @@ inst: } | LTYPE8 cond '[' reglist ']' ',' ioreg { - Gen g; + Addr g; g = nullgen; g.type = D_CONST; @@ -279,7 +279,7 @@ inst: */ | LTYPEJ cond con ',' expr ',' spreg ',' creg ',' creg oexpr { - Gen g; + Addr g; g = nullgen; g.type = D_CONST; @@ -294,7 +294,7 @@ inst: (($11 & 15) << 0) | /* Crm */ (($12 & 7) << 5) | /* coprocessor information */ (1<<4); /* must be set */ - outcode(AWORD, Always, &nullgen, NREG, &g); + outcode(AMRC, Always, &nullgen, NREG, &g); } /* * MULL r1,r2,(hi,lo) @@ -336,7 +336,7 @@ inst: { if($2.type != D_CONST) yyerror("index for FUNCDATA must be integer constant"); - if($4.type != D_EXTERN && $4.type != D_STATIC) + if($4.type != D_EXTERN && $4.type != D_STATIC && $4.type != D_OREG) yyerror("value for FUNCDATA must be symbol reference"); outcode($1, Always, &$2, NREG, &$4); } @@ -377,14 +377,12 @@ rel: if(pass == 2) yyerror("undefined label: %s", $1->name); $$.type = D_BRANCH; - $$.sym = $1; $$.offset = $2; } | LLAB offset { $$ = nullgen; $$.type = D_BRANCH; - $$.sym = $1; $$.offset = $1->value + $2; } @@ -408,7 +406,7 @@ ximm: '$' con { $$ = nullgen; $$.type = D_SCONST; - memcpy($$.sval, $2, sizeof($$.sval)); + memcpy($$.u.sval, $2, sizeof($$.u.sval)); } | fcon @@ -417,13 +415,13 @@ fcon: { $$ = nullgen; $$.type = D_FCONST; - $$.dval = $2; + $$.u.dval = $2; } | '$' '-' LFCONST { $$ = nullgen; $$.type = D_FCONST; - $$.dval = -$3; + $$.u.dval = -$3; } reglist: @@ -635,7 +633,7 @@ name: $$ = nullgen; $$.type = D_OREG; $$.name = $3; - $$.sym = S; + $$.sym = nil; $$.offset = $1; } | LNAME offset '(' pointer ')' @@ -643,7 +641,7 @@ name: $$ = nullgen; $$.type = D_OREG; $$.name = $4; - $$.sym = $1; + $$.sym = linklookup(ctxt, $1->name, 0); $$.offset = $2; } | LNAME '<' '>' offset '(' LSB ')' @@ -651,7 +649,7 @@ name: $$ = nullgen; $$.type = D_OREG; $$.name = D_STATIC; - $$.sym = $1; + $$.sym = linklookup(ctxt, $1->name, 1); $$.offset = $4; } diff --git a/src/cmd/5a/lex.c b/src/cmd/5a/lex.c index c1b54e50b..571fdf7f2 100644 --- a/src/cmd/5a/lex.c +++ b/src/cmd/5a/lex.c @@ -51,60 +51,76 @@ systemtype(int sys) #endif } +int +Lconv(Fmt *fp) +{ + return linklinefmt(ctxt, fp); +} + +void +dodef(char *p) +{ + if(nDlist%8 == 0) + Dlist = allocn(Dlist, nDlist*sizeof(char *), + 8*sizeof(char *)); + Dlist[nDlist++] = p; +} + +void +usage(void) +{ + print("usage: %ca [options] file.c...\n", thechar); + flagprint(1); + errorexit(); +} + void main(int argc, char *argv[]) { char *p; - int c; thechar = '5'; thestring = "arm"; + ctxt = linknew(&linkarm); + ctxt->diag = yyerror; + ctxt->bso = &bstdout; + Binit(&bstdout, 1, OWRITE); + listinit5(); + fmtinstall('L', Lconv); + + // Allow GOARCH=thestring or GOARCH=thestringsuffix, + // but not other values. + p = getgoarch(); + if(strncmp(p, thestring, strlen(thestring)) != 0) + sysfatal("cannot use %cc with GOARCH=%s", thechar, p); + ensuresymb(NSYMB); memset(debug, 0, sizeof(debug)); cinit(); outfile = 0; setinclude("."); - ARGBEGIN { - default: - c = ARGC(); - if(c >= 0 && c < sizeof(debug)) - debug[c] = 1; - break; - - case 'o': - outfile = ARGF(); - break; - - case 'D': - p = ARGF(); - if(p) { - if (nDlist%8 == 0) - Dlist = allocn(Dlist, nDlist*sizeof(char *), - 8*sizeof(char *)); - Dlist[nDlist++] = p; - } - break; - - case 'I': - p = ARGF(); - setinclude(p); - break; - case 't': - thechar = 't'; - thestring = "thumb"; - break; - } ARGEND - if(*argv == 0) { - print("usage: %ca [-options] file.s\n", thechar); - errorexit(); - } + + flagfn1("D", "name[=value]: add #define", dodef); + flagfn1("I", "dir: add dir to include path", setinclude); + flagcount("S", "print assembly and machine code", &debug['S']); + flagcount("m", "debug preprocessor macros", &debug['m']); + flagstr("o", "file: set output file", &outfile); + flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath); + + flagparse(&argc, &argv, usage); + ctxt->debugasm = debug['S']; + + if(argc < 1) + usage(); if(argc > 1){ print("can't assemble multiple files\n"); errorexit(); } + if(assemble(argv[0])) errorexit(); + Bflush(&bstdout); exits(0); } @@ -143,30 +159,22 @@ assemble(char *file) errorexit(); } Binit(&obuf, of, OWRITE); - - pass = 1; - pinit(file); - - Bprint(&obuf, "go object %s %s %s\n", getgoos(), thestring, getgoversion()); - - for(i=0; itype = itab[i].type; s->value = itab[i].value; } - - pathname = allocn(pathname, 0, 100); - if(getwd(pathname, 99) == 0) { - pathname = allocn(pathname, 100, 900); - if(getwd(pathname, 999) == 0) - strcpy(pathname, "/???"); - } } void @@ -466,7 +461,7 @@ syminit(Sym *s) } int -isreg(Gen *g) +isreg(Addr *g) { USED(g); @@ -476,81 +471,7 @@ isreg(Gen *g) void cclean(void) { - outcode(AEND, Always, &nullgen, NREG, &nullgen); - Bflush(&obuf); -} - -void -zname(char *n, int t, int s) -{ - - BPUTC(&obuf, ANAME); - BPUTC(&obuf, t); /* type */ - BPUTC(&obuf, s); /* sym */ - while(*n) { - BPUTC(&obuf, *n); - n++; - } - BPUTC(&obuf, 0); -} - -void -zaddr(Gen *a, int s) -{ - int32 l; - int i; - char *n; - Ieee e; - - BPUTC(&obuf, a->type); - BPUTC(&obuf, a->reg); - BPUTC(&obuf, s); - BPUTC(&obuf, a->name); - BPUTC(&obuf, 0); - switch(a->type) { - default: - print("unknown type %d\n", a->type); - exits("arg"); - - case D_NONE: - case D_REG: - case D_FREG: - case D_PSR: - case D_FPCR: - break; - - case D_REGREG: - case D_REGREG2: - BPUTC(&obuf, a->offset); - break; - - case D_CONST2: - l = a->offset2; - BPUTLE4(&obuf, l); - // fall through - case D_OREG: - case D_CONST: - case D_BRANCH: - case D_SHIFT: - l = a->offset; - BPUTLE4(&obuf, l); - break; - - case D_SCONST: - n = a->sval; - for(i=0; idval); - BPUTLE4(&obuf, e.l); - BPUTLE4(&obuf, e.h); - break; - } } static int bcode[] = @@ -573,11 +494,13 @@ static int bcode[] = ANOP, }; +static Prog *lastpc; + void -outcode(int a, int scond, Gen *g1, int reg, Gen *g2) +outcode(int a, int scond, Addr *g1, int reg, Addr *g2) { - int sf, st, t; - Sym *s; + Prog *p; + Plist *pl; /* hack to make B.NE etc. work: turn it into the corresponding conditional */ if(a == AB){ @@ -587,154 +510,28 @@ outcode(int a, int scond, Gen *g1, int reg, Gen *g2) if(pass == 1) goto out; -jackpot: - sf = 0; - s = g1->sym; - while(s != S) { - sf = s->sym; - if(sf < 0 || sf >= NSYM) - sf = 0; - t = g1->name; - if(h[sf].type == t) - if(h[sf].sym == s) - break; - zname(s->name, t, sym); - s->sym = sym; - h[sym].sym = s; - h[sym].type = t; - sf = sym; - sym++; - if(sym >= NSYM) - sym = 1; - break; - } - st = 0; - s = g2->sym; - while(s != S) { - st = s->sym; - if(st < 0 || st >= NSYM) - st = 0; - t = g2->name; - if(h[st].type == t) - if(h[st].sym == s) - break; - zname(s->name, t, sym); - s->sym = sym; - h[sym].sym = s; - h[sym].type = t; - st = sym; - sym++; - if(sym >= NSYM) - sym = 1; - if(st == sf) - goto jackpot; - break; - } - BPUTC(&obuf, a); - BPUTC(&obuf, scond); - BPUTC(&obuf, reg); - BPUTLE4(&obuf, stmtline); - zaddr(g1, sf); - zaddr(g2, st); + + p = malloc(sizeof *p); + memset(p, 0, sizeof *p); + p->as = a; + p->lineno = stmtline; + p->scond = scond; + p->from = *g1; + p->reg = reg; + p->to = *g2; + p->pc = pc; + + if(lastpc == nil) { + pl = linknewplist(ctxt); + pl->firstpc = p; + } else + lastpc->link = p; + lastpc = p; out: if(a != AGLOBL && a != ADATA) pc++; } -void -outhist(void) -{ - Gen g; - Hist *h; - char *p, *q, *op, c; - int n; - char *tofree; - static int first = 1; - static char *goroot, *goroot_final; - - if(first) { - // Decide whether we need to rewrite paths from $GOROOT to $GOROOT_FINAL. - first = 0; - goroot = getenv("GOROOT"); - goroot_final = getenv("GOROOT_FINAL"); - if(goroot == nil) - goroot = ""; - if(goroot_final == nil) - goroot_final = goroot; - if(strcmp(goroot, goroot_final) == 0) { - goroot = nil; - goroot_final = nil; - } - } - - tofree = nil; - g = nullgen; - c = '/'; - for(h = hist; h != H; h = h->link) { - p = h->name; - if(p != nil && goroot != nil) { - n = strlen(goroot); - if(strncmp(p, goroot, strlen(goroot)) == 0 && p[n] == '/') { - tofree = smprint("%s%s", goroot_final, p+n); - p = tofree; - } - } - op = 0; - if(systemtype(Windows) && p && p[1] == ':'){ - c = p[2]; - } else if(p && p[0] != c && h->offset == 0 && pathname){ - if(systemtype(Windows) && pathname[1] == ':') { - op = p; - p = pathname; - c = p[2]; - } else if(pathname[0] == c){ - op = p; - p = pathname; - } - } - while(p) { - q = strchr(p, c); - if(q) { - n = q-p; - if(n == 0){ - n = 1; /* leading "/" */ - *p = '/'; /* don't emit "\" on windows */ - } - q++; - } else { - n = strlen(p); - q = 0; - } - if(n) { - BPUTC(&obuf, ANAME); - BPUTC(&obuf, D_FILE); /* type */ - BPUTC(&obuf, 1); /* sym */ - BPUTC(&obuf, '<'); - Bwrite(&obuf, p, n); - BPUTC(&obuf, 0); - } - p = q; - if(p == 0 && op) { - p = op; - op = 0; - } - } - g.offset = h->offset; - - BPUTC(&obuf, AHISTORY); - BPUTC(&obuf, Always); - BPUTC(&obuf, 0); - BPUTLE4(&obuf, h->line); - zaddr(&nullgen, 0); - zaddr(&g, 0); - - if(tofree) { - free(tofree); - tofree = nil; - } - } -} - #include "../cc/lexbody" #include "../cc/macbody" diff --git a/src/cmd/5a/y.tab.c b/src/cmd/5a/y.tab.c index dd102a09a..0bc8c34e1 100644 --- a/src/cmd/5a/y.tab.c +++ b/src/cmd/5a/y.tab.c @@ -1,8 +1,8 @@ -/* A Bison parser, made by GNU Bison 2.5. */ +/* A Bison parser, made by GNU Bison 2.7.12-4996. */ /* Bison implementation for Yacc-like parsers in C - Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc. + Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -44,7 +44,7 @@ #define YYBISON 1 /* Bison version. */ -#define YYBISON_VERSION "2.5" +#define YYBISON_VERSION "2.7.12-4996" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -58,14 +58,11 @@ /* Pull parsers. */ #define YYPULL 1 -/* Using locations. */ -#define YYLSP_NEEDED 0 /* Copy the first part of user declarations. */ - -/* Line 268 of yacc.c */ +/* Line 371 of yacc.c */ #line 31 "a.y" #include @@ -74,14 +71,16 @@ #include "a.h" #include "../../pkg/runtime/funcdata.h" +/* Line 371 of yacc.c */ +#line 76 "y.tab.c" -/* Line 268 of yacc.c */ -#line 80 "y.tab.c" - -/* Enabling traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif +# ifndef YY_NULL +# if defined __cplusplus && 201103L <= __cplusplus +# define YY_NULL nullptr +# else +# define YY_NULL 0 +# endif +# endif /* Enabling verbose error messages. */ #ifdef YYERROR_VERBOSE @@ -91,11 +90,17 @@ # define YYERROR_VERBOSE 0 #endif -/* Enabling the token table. */ -#ifndef YYTOKEN_TABLE -# define YYTOKEN_TABLE 0 +/* In a future release of Bison, this section will be replaced + by #include "y.tab.h". */ +#ifndef YY_YY_Y_TAB_H_INCLUDED +# define YY_YY_Y_TAB_H_INCLUDED +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int yydebug; #endif - /* Tokens. */ #ifndef YYTOKENTYPE @@ -205,36 +210,49 @@ - #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE { - -/* Line 293 of yacc.c */ +/* Line 387 of yacc.c */ #line 39 "a.y" Sym *sym; int32 lval; double dval; char sval[8]; - Gen gen; + Addr addr; - -/* Line 293 of yacc.c */ -#line 226 "y.tab.c" +/* Line 387 of yacc.c */ +#line 228 "y.tab.c" } YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 #endif +extern YYSTYPE yylval; -/* Copy the second part of user declarations. */ +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + +#endif /* !YY_YY_Y_TAB_H_INCLUDED */ +/* Copy the second part of user declarations. */ -/* Line 343 of yacc.c */ -#line 238 "y.tab.c" +/* Line 390 of yacc.c */ +#line 256 "y.tab.c" #ifdef short # undef short @@ -287,24 +305,33 @@ typedef short int yytype_int16; # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ -# define YY_(msgid) dgettext ("bison-runtime", msgid) +# define YY_(Msgid) dgettext ("bison-runtime", Msgid) # endif # endif # ifndef YY_ -# define YY_(msgid) msgid +# define YY_(Msgid) Msgid +# endif +#endif + +#ifndef __attribute__ +/* This feature is available in gcc versions 2.5 and later. */ +# if (! defined __GNUC__ || __GNUC__ < 2 \ + || (__GNUC__ == 2 && __GNUC_MINOR__ < 5)) +# define __attribute__(Spec) /* empty */ # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ -# define YYUSE(e) ((void) (e)) +# define YYUSE(E) ((void) (E)) #else -# define YYUSE(e) /* empty */ +# define YYUSE(E) /* empty */ #endif + /* Identity function, used to suppress warnings about constant conditions. */ #ifndef lint -# define YYID(n) (n) +# define YYID(N) (N) #else #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) @@ -340,6 +367,7 @@ YYID (yyi) # if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) # include /* INFRINGES ON USER NAME SPACE */ + /* Use EXIT_SUCCESS as a witness for stdlib.h. */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif @@ -431,20 +459,20 @@ union yyalloc #endif #if defined YYCOPY_NEEDED && YYCOPY_NEEDED -/* Copy COUNT objects from FROM to TO. The source and destination do +/* Copy COUNT objects from SRC to DST. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ -# define YYCOPY(To, From, Count) \ - __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# define YYCOPY(Dst, Src, Count) \ + __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) # else -# define YYCOPY(To, From, Count) \ - do \ - { \ - YYSIZE_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (To)[yyi] = (From)[yyi]; \ - } \ +# define YYCOPY(Dst, Src, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (Dst)[yyi] = (Src)[yyi]; \ + } \ while (YYID (0)) # endif # endif @@ -594,19 +622,19 @@ static const yytype_uint16 yyrline[] = 141, 148, 155, 162, 169, 176, 185, 197, 201, 205, 212, 219, 225, 231, 240, 247, 254, 261, 265, 269, 273, 280, 302, 310, 319, 326, 335, 346, 352, 355, - 359, 364, 365, 368, 374, 383, 391, 397, 402, 407, - 413, 416, 422, 430, 434, 443, 449, 450, 451, 452, - 457, 463, 469, 475, 476, 479, 480, 488, 497, 498, - 507, 508, 514, 517, 518, 519, 521, 529, 537, 546, - 552, 558, 564, 572, 578, 586, 587, 591, 599, 600, - 606, 607, 615, 616, 619, 625, 633, 641, 649, 659, - 662, 666, 672, 673, 674, 677, 678, 682, 686, 690, - 694, 700, 703, 709, 710, 714, 718, 722, 726, 730, - 734, 738, 742, 746 + 359, 364, 365, 368, 374, 382, 389, 395, 400, 405, + 411, 414, 420, 428, 432, 441, 447, 448, 449, 450, + 455, 461, 467, 473, 474, 477, 478, 486, 495, 496, + 505, 506, 512, 515, 516, 517, 519, 527, 535, 544, + 550, 556, 562, 570, 576, 584, 585, 589, 597, 598, + 604, 605, 613, 614, 617, 623, 631, 639, 647, 657, + 660, 664, 670, 671, 672, 675, 676, 680, 684, 688, + 692, 698, 701, 707, 708, 712, 716, 720, 724, 728, + 732, 736, 740, 744 }; #endif -#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +#if YYDEBUG || YYERROR_VERBOSE || 0 /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = @@ -623,7 +651,7 @@ static const char *const yytname[] = "$@1", "line", "$@2", "$@3", "inst", "cond", "comma", "rel", "ximm", "fcon", "reglist", "gen", "nireg", "ireg", "ioreg", "oreg", "imsr", "imm", "reg", "regreg", "shift", "rcon", "sreg", "spreg", "creg", - "frcon", "freg", "name", "offset", "pointer", "con", "oexpr", "expr", 0 + "frcon", "freg", "name", "offset", "pointer", "con", "oexpr", "expr", YY_NULL }; #endif @@ -850,10 +878,10 @@ static const yytype_int16 yytable[] = 202, 203, 204, 198, 199, 200, 201, 202, 203, 204 }; -#define yypact_value_is_default(yystate) \ - ((yystate) == (-128)) +#define yypact_value_is_default(Yystate) \ + (!!((Yystate) == (-128))) -#define yytable_value_is_error(yytable_value) \ +#define yytable_value_is_error(Yytable_value) \ YYID (0) static const yytype_int16 yycheck[] = @@ -988,62 +1016,35 @@ static const yytype_uint8 yystos[] = #define YYRECOVERING() (!!yyerrstatus) -#define YYBACKUP(Token, Value) \ -do \ - if (yychar == YYEMPTY && yylen == 1) \ - { \ - yychar = (Token); \ - yylval = (Value); \ - YYPOPSTACK (1); \ - goto yybackup; \ - } \ - else \ - { \ +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } \ + else \ + { \ yyerror (YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (YYID (0)) - +/* Error token number */ #define YYTERROR 1 #define YYERRCODE 256 -/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. - If N is 0, then set CURRENT to the empty location which ends - the previous symbol: RHS[0] (always defined). */ - -#define YYRHSLOC(Rhs, K) ((Rhs)[K]) -#ifndef YYLLOC_DEFAULT -# define YYLLOC_DEFAULT(Current, Rhs, N) \ - do \ - if (YYID (N)) \ - { \ - (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ - (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ - (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ - (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ - } \ - else \ - { \ - (Current).first_line = (Current).last_line = \ - YYRHSLOC (Rhs, 0).last_line; \ - (Current).first_column = (Current).last_column = \ - YYRHSLOC (Rhs, 0).last_column; \ - } \ - while (YYID (0)) -#endif - - /* This macro is provided for backward compatibility. */ - #ifndef YY_LOCATION_PRINT # define YY_LOCATION_PRINT(File, Loc) ((void) 0) #endif /* YYLEX -- calling `yylex' with the right arguments. */ - #ifdef YYLEX_PARAM # define YYLEX yylex (YYLEX_PARAM) #else @@ -1093,6 +1094,8 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep) YYSTYPE const * const yyvaluep; #endif { + FILE *yyo = yyoutput; + YYUSE (yyo); if (!yyvaluep) return; # ifdef YYPRINT @@ -1101,11 +1104,7 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep) # else YYUSE (yyoutput); # endif - switch (yytype) - { - default: - break; - } + YYUSE (yytype); } @@ -1344,12 +1343,11 @@ static int yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, yytype_int16 *yyssp, int yytoken) { - YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]); + YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]); YYSIZE_T yysize = yysize0; - YYSIZE_T yysize1; enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; /* Internationalized format string. */ - const char *yyformat = 0; + const char *yyformat = YY_NULL; /* Arguments of yyformat. */ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; /* Number of reported tokens (one for the "unexpected", one per @@ -1409,11 +1407,13 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, break; } yyarg[yycount++] = yytname[yyx]; - yysize1 = yysize + yytnamerr (0, yytname[yyx]); - if (! (yysize <= yysize1 - && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) - return 2; - yysize = yysize1; + { + YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]); + if (! (yysize <= yysize1 + && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } } } } @@ -1433,10 +1433,12 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, # undef YYCASE_ } - yysize1 = yysize + yystrlen (yyformat); - if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) - return 2; - yysize = yysize1; + { + YYSIZE_T yysize1 = yysize + yystrlen (yyformat); + if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } if (*yymsg_alloc < yysize) { @@ -1492,36 +1494,26 @@ yydestruct (yymsg, yytype, yyvaluep) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); - switch (yytype) - { - - default: - break; - } + YYUSE (yytype); } -/* Prevent warnings from -Wmissing-prototypes. */ -#ifdef YYPARSE_PARAM -#if defined __STDC__ || defined __cplusplus -int yyparse (void *YYPARSE_PARAM); -#else -int yyparse (); -#endif -#else /* ! YYPARSE_PARAM */ -#if defined __STDC__ || defined __cplusplus -int yyparse (void); -#else -int yyparse (); -#endif -#endif /* ! YYPARSE_PARAM */ /* The lookahead symbol. */ int yychar; + +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + /* The semantic value of the lookahead symbol. */ -YYSTYPE yylval; +YYSTYPE yylval YY_INITIAL_VALUE(yyval_default); /* Number of syntax errors so far. */ int yynerrs; @@ -1561,7 +1553,7 @@ yyparse () `yyss': related to states. `yyvs': related to semantic values. - Refer to the stacks thru separate pointers, to allow yyoverflow + Refer to the stacks through separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* The state stack. */ @@ -1579,7 +1571,7 @@ yyparse () int yyn; int yyresult; /* Lookahead token as an internal (translated) token number. */ - int yytoken; + int yytoken = 0; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; @@ -1597,9 +1589,8 @@ yyparse () Keep to zero when no symbol should be popped. */ int yylen = 0; - yytoken = 0; - yyss = yyssa; - yyvs = yyvsa; + yyssp = yyss = yyssa; + yyvsp = yyvs = yyvsa; yystacksize = YYINITDEPTH; YYDPRINTF ((stderr, "Starting parse\n")); @@ -1608,14 +1599,6 @@ yyparse () yyerrstatus = 0; yynerrs = 0; yychar = YYEMPTY; /* Cause a token to be read. */ - - /* Initialize stack pointers. - Waste one element of value and location stack - so that they stay on the same level as the state stack. - The wasted elements are never initialized. */ - yyssp = yyss; - yyvsp = yyvs; - goto yysetstate; /*------------------------------------------------------------. @@ -1756,7 +1739,9 @@ yybackup: yychar = YYEMPTY; yystate = yyn; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END goto yynewstate; @@ -1793,8 +1778,7 @@ yyreduce: switch (yyn) { case 3: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 70 "a.y" { stmtline = lineno; @@ -1802,8 +1786,7 @@ yyreduce: break; case 5: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 77 "a.y" { if((yyvsp[(1) - (2)].sym)->value != pc) @@ -1813,8 +1796,7 @@ yyreduce: break; case 7: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 84 "a.y" { (yyvsp[(1) - (2)].sym)->type = LLAB; @@ -1823,8 +1805,7 @@ yyreduce: break; case 9: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 90 "a.y" { (yyvsp[(1) - (4)].sym)->type = LVAR; @@ -1833,8 +1814,7 @@ yyreduce: break; case 10: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 95 "a.y" { if((yyvsp[(1) - (4)].sym)->value != (yyvsp[(3) - (4)].lval)) @@ -1844,162 +1824,145 @@ yyreduce: break; case 14: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 109 "a.y" { - outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].gen), (yyvsp[(5) - (7)].lval), &(yyvsp[(7) - (7)].gen)); + outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].addr), (yyvsp[(5) - (7)].lval), &(yyvsp[(7) - (7)].addr)); } break; case 15: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 113 "a.y" { - outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(3) - (6)].gen), (yyvsp[(5) - (6)].lval), &nullgen); + outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(3) - (6)].addr), (yyvsp[(5) - (6)].lval), &nullgen); } break; case 16: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 117 "a.y" { - outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].gen), NREG, &(yyvsp[(5) - (5)].gen)); + outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), NREG, &(yyvsp[(5) - (5)].addr)); } break; case 17: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 124 "a.y" { - outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].gen), NREG, &(yyvsp[(5) - (5)].gen)); + outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), NREG, &(yyvsp[(5) - (5)].addr)); } break; case 18: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 131 "a.y" { - outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].gen), NREG, &(yyvsp[(5) - (5)].gen)); + outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), NREG, &(yyvsp[(5) - (5)].addr)); } break; case 19: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 138 "a.y" { - outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, NREG, &(yyvsp[(4) - (4)].gen)); + outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, NREG, &(yyvsp[(4) - (4)].addr)); } break; case 20: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 142 "a.y" { - outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, NREG, &(yyvsp[(4) - (4)].gen)); + outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, NREG, &(yyvsp[(4) - (4)].addr)); } break; case 21: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 149 "a.y" { - outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, NREG, &(yyvsp[(3) - (3)].gen)); + outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, NREG, &(yyvsp[(3) - (3)].addr)); } break; case 22: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 156 "a.y" { - outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, NREG, &(yyvsp[(3) - (3)].gen)); + outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, NREG, &(yyvsp[(3) - (3)].addr)); } break; case 23: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 163 "a.y" { - outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, NREG, &(yyvsp[(4) - (4)].gen)); + outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, NREG, &(yyvsp[(4) - (4)].addr)); } break; case 24: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 170 "a.y" { - outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(3) - (6)].gen), (yyvsp[(5) - (6)].lval), &nullgen); + outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(3) - (6)].addr), (yyvsp[(5) - (6)].lval), &nullgen); } break; case 25: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 177 "a.y" { - Gen g; + Addr g; g = nullgen; g.type = D_CONST; g.offset = (yyvsp[(6) - (7)].lval); - outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].gen), NREG, &g); + outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].addr), NREG, &g); } break; case 26: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 186 "a.y" { - Gen g; + Addr g; g = nullgen; g.type = D_CONST; g.offset = (yyvsp[(4) - (7)].lval); - outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &g, NREG, &(yyvsp[(7) - (7)].gen)); + outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &g, NREG, &(yyvsp[(7) - (7)].addr)); } break; case 27: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 198 "a.y" { - outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(5) - (7)].gen), (yyvsp[(3) - (7)].gen).reg, &(yyvsp[(7) - (7)].gen)); + outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(5) - (7)].addr), (yyvsp[(3) - (7)].addr).reg, &(yyvsp[(7) - (7)].addr)); } break; case 28: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 202 "a.y" { - outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(5) - (6)].gen), (yyvsp[(3) - (6)].gen).reg, &(yyvsp[(3) - (6)].gen)); + outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(5) - (6)].addr), (yyvsp[(3) - (6)].addr).reg, &(yyvsp[(3) - (6)].addr)); } break; case 29: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 206 "a.y" { - outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(4) - (6)].gen), (yyvsp[(6) - (6)].gen).reg, &(yyvsp[(6) - (6)].gen)); + outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(4) - (6)].addr), (yyvsp[(6) - (6)].addr).reg, &(yyvsp[(6) - (6)].addr)); } break; case 30: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 213 "a.y" { outcode((yyvsp[(1) - (3)].lval), (yyvsp[(2) - (3)].lval), &nullgen, NREG, &nullgen); @@ -2007,107 +1970,96 @@ yyreduce: break; case 31: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 220 "a.y" { - (yyvsp[(4) - (4)].gen).type = D_CONST2; - (yyvsp[(4) - (4)].gen).offset2 = ArgsSizeUnknown; - outcode((yyvsp[(1) - (4)].lval), Always, &(yyvsp[(2) - (4)].gen), 0, &(yyvsp[(4) - (4)].gen)); + (yyvsp[(4) - (4)].addr).type = D_CONST2; + (yyvsp[(4) - (4)].addr).offset2 = ArgsSizeUnknown; + outcode((yyvsp[(1) - (4)].lval), Always, &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); } break; case 32: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 226 "a.y" { - (yyvsp[(6) - (6)].gen).type = D_CONST2; - (yyvsp[(6) - (6)].gen).offset2 = ArgsSizeUnknown; - outcode((yyvsp[(1) - (6)].lval), Always, &(yyvsp[(2) - (6)].gen), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].gen)); + (yyvsp[(6) - (6)].addr).type = D_CONST2; + (yyvsp[(6) - (6)].addr).offset2 = ArgsSizeUnknown; + outcode((yyvsp[(1) - (6)].lval), Always, &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr)); } break; case 33: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 232 "a.y" { - (yyvsp[(6) - (8)].gen).type = D_CONST2; - (yyvsp[(6) - (8)].gen).offset2 = (yyvsp[(8) - (8)].lval); - outcode((yyvsp[(1) - (8)].lval), Always, &(yyvsp[(2) - (8)].gen), (yyvsp[(4) - (8)].lval), &(yyvsp[(6) - (8)].gen)); + (yyvsp[(6) - (8)].addr).type = D_CONST2; + (yyvsp[(6) - (8)].addr).offset2 = (yyvsp[(8) - (8)].lval); + outcode((yyvsp[(1) - (8)].lval), Always, &(yyvsp[(2) - (8)].addr), (yyvsp[(4) - (8)].lval), &(yyvsp[(6) - (8)].addr)); } break; case 34: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 241 "a.y" { - outcode((yyvsp[(1) - (6)].lval), Always, &(yyvsp[(2) - (6)].gen), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].gen)); + outcode((yyvsp[(1) - (6)].lval), Always, &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr)); } break; case 35: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 248 "a.y" { - outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &(yyvsp[(3) - (4)].gen), NREG, &nullgen); + outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &(yyvsp[(3) - (4)].addr), NREG, &nullgen); } break; case 36: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 255 "a.y" { - outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, NREG, &(yyvsp[(3) - (3)].gen)); + outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, NREG, &(yyvsp[(3) - (3)].addr)); } break; case 37: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 262 "a.y" { - outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].gen), NREG, &(yyvsp[(5) - (5)].gen)); + outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), NREG, &(yyvsp[(5) - (5)].addr)); } break; case 38: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 266 "a.y" { - outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].gen), NREG, &(yyvsp[(5) - (5)].gen)); + outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), NREG, &(yyvsp[(5) - (5)].addr)); } break; case 39: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 270 "a.y" { - outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].gen), (yyvsp[(5) - (7)].lval), &(yyvsp[(7) - (7)].gen)); + outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].addr), (yyvsp[(5) - (7)].lval), &(yyvsp[(7) - (7)].addr)); } break; case 40: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 274 "a.y" { - outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(3) - (6)].gen), (yyvsp[(5) - (6)].gen).reg, &nullgen); + outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(3) - (6)].addr), (yyvsp[(5) - (6)].addr).reg, &nullgen); } break; case 41: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 281 "a.y" { - Gen g; + Addr g; g = nullgen; g.type = D_CONST; @@ -2122,66 +2074,60 @@ yyreduce: (((yyvsp[(11) - (12)].lval) & 15) << 0) | /* Crm */ (((yyvsp[(12) - (12)].lval) & 7) << 5) | /* coprocessor information */ (1<<4); /* must be set */ - outcode(AWORD, Always, &nullgen, NREG, &g); + outcode(AMRC, Always, &nullgen, NREG, &g); } break; case 42: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 303 "a.y" { - outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].gen), (yyvsp[(5) - (7)].gen).reg, &(yyvsp[(7) - (7)].gen)); + outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].addr), (yyvsp[(5) - (7)].addr).reg, &(yyvsp[(7) - (7)].addr)); } break; case 43: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 311 "a.y" { - (yyvsp[(7) - (9)].gen).type = D_REGREG2; - (yyvsp[(7) - (9)].gen).offset = (yyvsp[(9) - (9)].lval); - outcode((yyvsp[(1) - (9)].lval), (yyvsp[(2) - (9)].lval), &(yyvsp[(3) - (9)].gen), (yyvsp[(5) - (9)].gen).reg, &(yyvsp[(7) - (9)].gen)); + (yyvsp[(7) - (9)].addr).type = D_REGREG2; + (yyvsp[(7) - (9)].addr).offset = (yyvsp[(9) - (9)].lval); + outcode((yyvsp[(1) - (9)].lval), (yyvsp[(2) - (9)].lval), &(yyvsp[(3) - (9)].addr), (yyvsp[(5) - (9)].addr).reg, &(yyvsp[(7) - (9)].addr)); } break; case 44: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 320 "a.y" { - outcode((yyvsp[(1) - (2)].lval), Always, &(yyvsp[(2) - (2)].gen), NREG, &nullgen); + outcode((yyvsp[(1) - (2)].lval), Always, &(yyvsp[(2) - (2)].addr), NREG, &nullgen); } break; case 45: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 327 "a.y" { - if((yyvsp[(2) - (4)].gen).type != D_CONST || (yyvsp[(4) - (4)].gen).type != D_CONST) + if((yyvsp[(2) - (4)].addr).type != D_CONST || (yyvsp[(4) - (4)].addr).type != D_CONST) yyerror("arguments to PCDATA must be integer constants"); - outcode((yyvsp[(1) - (4)].lval), Always, &(yyvsp[(2) - (4)].gen), NREG, &(yyvsp[(4) - (4)].gen)); + outcode((yyvsp[(1) - (4)].lval), Always, &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr)); } break; case 46: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 336 "a.y" { - if((yyvsp[(2) - (4)].gen).type != D_CONST) + if((yyvsp[(2) - (4)].addr).type != D_CONST) yyerror("index for FUNCDATA must be integer constant"); - if((yyvsp[(4) - (4)].gen).type != D_EXTERN && (yyvsp[(4) - (4)].gen).type != D_STATIC) + if((yyvsp[(4) - (4)].addr).type != D_EXTERN && (yyvsp[(4) - (4)].addr).type != D_STATIC && (yyvsp[(4) - (4)].addr).type != D_OREG) yyerror("value for FUNCDATA must be symbol reference"); - outcode((yyvsp[(1) - (4)].lval), Always, &(yyvsp[(2) - (4)].gen), NREG, &(yyvsp[(4) - (4)].gen)); + outcode((yyvsp[(1) - (4)].lval), Always, &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr)); } break; case 47: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 347 "a.y" { outcode((yyvsp[(1) - (2)].lval), Always, &nullgen, NREG, &nullgen); @@ -2189,8 +2135,7 @@ yyreduce: break; case 48: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 352 "a.y" { (yyval.lval) = Always; @@ -2198,8 +2143,7 @@ yyreduce: break; case 49: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 356 "a.y" { (yyval.lval) = ((yyvsp[(1) - (2)].lval) & ~C_SCOND) | (yyvsp[(2) - (2)].lval); @@ -2207,8 +2151,7 @@ yyreduce: break; case 50: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 360 "a.y" { (yyval.lval) = (yyvsp[(1) - (2)].lval) | (yyvsp[(2) - (2)].lval); @@ -2216,119 +2159,106 @@ yyreduce: break; case 53: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 369 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_BRANCH; - (yyval.gen).offset = (yyvsp[(1) - (4)].lval) + pc; + (yyval.addr) = nullgen; + (yyval.addr).type = D_BRANCH; + (yyval.addr).offset = (yyvsp[(1) - (4)].lval) + pc; } break; case 54: - -/* Line 1806 of yacc.c */ +/* Line 1787 of yacc.c */ #line 375 "a.y" { - (yyval.gen) = nullgen; + (yyval.addr) = nullgen; if(pass == 2) yyerror("undefined label: %s", (yyvsp[(1) - (2)].sym)->name); - (yyval.gen).type = D_BRANCH; - (yyval.gen).sym = (yyvsp[(1) - (2)].sym); - (yyval.gen).offset = (yyvsp[(2) - (2)].lval); + (yyval.addr).type = D_BRANCH; + (yyval.addr).offset = (yyvsp[(2) - (2)].lval); } break; case 55: - -/* Line 1806 of yacc.c */ -#line 384 "a.y" +/* Line 1787 of yacc.c */ +#line 383 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_BRANCH; - (yyval.gen).sym = (yyvsp[(1) - (2)].sym); - (yyval.gen).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_BRANCH; + (yyval.addr).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval); } break; case 56: - -/* Line 1806 of yacc.c */ -#line 392 "a.y" +/* Line 1787 of yacc.c */ +#line 390 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_CONST; - (yyval.gen).offset = (yyvsp[(2) - (2)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_CONST; + (yyval.addr).offset = (yyvsp[(2) - (2)].lval); } break; case 57: - -/* Line 1806 of yacc.c */ -#line 398 "a.y" +/* Line 1787 of yacc.c */ +#line 396 "a.y" { - (yyval.gen) = (yyvsp[(2) - (2)].gen); - (yyval.gen).type = D_CONST; + (yyval.addr) = (yyvsp[(2) - (2)].addr); + (yyval.addr).type = D_CONST; } break; case 58: - -/* Line 1806 of yacc.c */ -#line 403 "a.y" +/* Line 1787 of yacc.c */ +#line 401 "a.y" { - (yyval.gen) = (yyvsp[(4) - (4)].gen); - (yyval.gen).type = D_OCONST; + (yyval.addr) = (yyvsp[(4) - (4)].addr); + (yyval.addr).type = D_OCONST; } break; case 59: - -/* Line 1806 of yacc.c */ -#line 408 "a.y" +/* Line 1787 of yacc.c */ +#line 406 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_SCONST; - memcpy((yyval.gen).sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.gen).sval)); + (yyval.addr) = nullgen; + (yyval.addr).type = D_SCONST; + memcpy((yyval.addr).u.sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.addr).u.sval)); } break; case 61: - -/* Line 1806 of yacc.c */ -#line 417 "a.y" +/* Line 1787 of yacc.c */ +#line 415 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_FCONST; - (yyval.gen).dval = (yyvsp[(2) - (2)].dval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_FCONST; + (yyval.addr).u.dval = (yyvsp[(2) - (2)].dval); } break; case 62: - -/* Line 1806 of yacc.c */ -#line 423 "a.y" +/* Line 1787 of yacc.c */ +#line 421 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_FCONST; - (yyval.gen).dval = -(yyvsp[(3) - (3)].dval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_FCONST; + (yyval.addr).u.dval = -(yyvsp[(3) - (3)].dval); } break; case 63: - -/* Line 1806 of yacc.c */ -#line 431 "a.y" +/* Line 1787 of yacc.c */ +#line 429 "a.y" { (yyval.lval) = 1 << (yyvsp[(1) - (1)].lval); } break; case 64: - -/* Line 1806 of yacc.c */ -#line 435 "a.y" +/* Line 1787 of yacc.c */ +#line 433 "a.y" { int i; (yyval.lval)=0; @@ -2340,185 +2270,168 @@ yyreduce: break; case 65: - -/* Line 1806 of yacc.c */ -#line 444 "a.y" +/* Line 1787 of yacc.c */ +#line 442 "a.y" { (yyval.lval) = (1<<(yyvsp[(1) - (3)].lval)) | (yyvsp[(3) - (3)].lval); } break; case 69: - -/* Line 1806 of yacc.c */ -#line 453 "a.y" +/* Line 1787 of yacc.c */ +#line 451 "a.y" { - (yyval.gen) = (yyvsp[(1) - (4)].gen); - (yyval.gen).reg = (yyvsp[(3) - (4)].lval); + (yyval.addr) = (yyvsp[(1) - (4)].addr); + (yyval.addr).reg = (yyvsp[(3) - (4)].lval); } break; case 70: - -/* Line 1806 of yacc.c */ -#line 458 "a.y" +/* Line 1787 of yacc.c */ +#line 456 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_PSR; - (yyval.gen).reg = (yyvsp[(1) - (1)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_PSR; + (yyval.addr).reg = (yyvsp[(1) - (1)].lval); } break; case 71: - -/* Line 1806 of yacc.c */ -#line 464 "a.y" +/* Line 1787 of yacc.c */ +#line 462 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_FPCR; - (yyval.gen).reg = (yyvsp[(1) - (1)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_FPCR; + (yyval.addr).reg = (yyvsp[(1) - (1)].lval); } break; case 72: - -/* Line 1806 of yacc.c */ -#line 470 "a.y" +/* Line 1787 of yacc.c */ +#line 468 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_OREG; - (yyval.gen).offset = (yyvsp[(1) - (1)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_OREG; + (yyval.addr).offset = (yyvsp[(1) - (1)].lval); } break; case 76: - -/* Line 1806 of yacc.c */ -#line 481 "a.y" +/* Line 1787 of yacc.c */ +#line 479 "a.y" { - (yyval.gen) = (yyvsp[(1) - (1)].gen); - if((yyvsp[(1) - (1)].gen).name != D_EXTERN && (yyvsp[(1) - (1)].gen).name != D_STATIC) { + (yyval.addr) = (yyvsp[(1) - (1)].addr); + if((yyvsp[(1) - (1)].addr).name != D_EXTERN && (yyvsp[(1) - (1)].addr).name != D_STATIC) { } } break; case 77: - -/* Line 1806 of yacc.c */ -#line 489 "a.y" +/* Line 1787 of yacc.c */ +#line 487 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_OREG; - (yyval.gen).reg = (yyvsp[(2) - (3)].lval); - (yyval.gen).offset = 0; + (yyval.addr) = nullgen; + (yyval.addr).type = D_OREG; + (yyval.addr).reg = (yyvsp[(2) - (3)].lval); + (yyval.addr).offset = 0; } break; case 79: - -/* Line 1806 of yacc.c */ -#line 499 "a.y" +/* Line 1787 of yacc.c */ +#line 497 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_OREG; - (yyval.gen).reg = (yyvsp[(3) - (4)].lval); - (yyval.gen).offset = (yyvsp[(1) - (4)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_OREG; + (yyval.addr).reg = (yyvsp[(3) - (4)].lval); + (yyval.addr).offset = (yyvsp[(1) - (4)].lval); } break; case 81: - -/* Line 1806 of yacc.c */ -#line 509 "a.y" +/* Line 1787 of yacc.c */ +#line 507 "a.y" { - (yyval.gen) = (yyvsp[(1) - (4)].gen); - (yyval.gen).type = D_OREG; - (yyval.gen).reg = (yyvsp[(3) - (4)].lval); + (yyval.addr) = (yyvsp[(1) - (4)].addr); + (yyval.addr).type = D_OREG; + (yyval.addr).reg = (yyvsp[(3) - (4)].lval); } break; case 86: - -/* Line 1806 of yacc.c */ -#line 522 "a.y" +/* Line 1787 of yacc.c */ +#line 520 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_CONST; - (yyval.gen).offset = (yyvsp[(2) - (2)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_CONST; + (yyval.addr).offset = (yyvsp[(2) - (2)].lval); } break; case 87: - -/* Line 1806 of yacc.c */ -#line 530 "a.y" +/* Line 1787 of yacc.c */ +#line 528 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_REG; - (yyval.gen).reg = (yyvsp[(1) - (1)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_REG; + (yyval.addr).reg = (yyvsp[(1) - (1)].lval); } break; case 88: - -/* Line 1806 of yacc.c */ -#line 538 "a.y" +/* Line 1787 of yacc.c */ +#line 536 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_REGREG; - (yyval.gen).reg = (yyvsp[(2) - (5)].lval); - (yyval.gen).offset = (yyvsp[(4) - (5)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_REGREG; + (yyval.addr).reg = (yyvsp[(2) - (5)].lval); + (yyval.addr).offset = (yyvsp[(4) - (5)].lval); } break; case 89: - -/* Line 1806 of yacc.c */ -#line 547 "a.y" +/* Line 1787 of yacc.c */ +#line 545 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_SHIFT; - (yyval.gen).offset = (yyvsp[(1) - (4)].lval) | (yyvsp[(4) - (4)].lval) | (0 << 5); + (yyval.addr) = nullgen; + (yyval.addr).type = D_SHIFT; + (yyval.addr).offset = (yyvsp[(1) - (4)].lval) | (yyvsp[(4) - (4)].lval) | (0 << 5); } break; case 90: - -/* Line 1806 of yacc.c */ -#line 553 "a.y" +/* Line 1787 of yacc.c */ +#line 551 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_SHIFT; - (yyval.gen).offset = (yyvsp[(1) - (4)].lval) | (yyvsp[(4) - (4)].lval) | (1 << 5); + (yyval.addr) = nullgen; + (yyval.addr).type = D_SHIFT; + (yyval.addr).offset = (yyvsp[(1) - (4)].lval) | (yyvsp[(4) - (4)].lval) | (1 << 5); } break; case 91: - -/* Line 1806 of yacc.c */ -#line 559 "a.y" +/* Line 1787 of yacc.c */ +#line 557 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_SHIFT; - (yyval.gen).offset = (yyvsp[(1) - (4)].lval) | (yyvsp[(4) - (4)].lval) | (2 << 5); + (yyval.addr) = nullgen; + (yyval.addr).type = D_SHIFT; + (yyval.addr).offset = (yyvsp[(1) - (4)].lval) | (yyvsp[(4) - (4)].lval) | (2 << 5); } break; case 92: - -/* Line 1806 of yacc.c */ -#line 565 "a.y" +/* Line 1787 of yacc.c */ +#line 563 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_SHIFT; - (yyval.gen).offset = (yyvsp[(1) - (4)].lval) | (yyvsp[(4) - (4)].lval) | (3 << 5); + (yyval.addr) = nullgen; + (yyval.addr).type = D_SHIFT; + (yyval.addr).offset = (yyvsp[(1) - (4)].lval) | (yyvsp[(4) - (4)].lval) | (3 << 5); } break; case 93: - -/* Line 1806 of yacc.c */ -#line 573 "a.y" +/* Line 1787 of yacc.c */ +#line 571 "a.y" { if((yyval.lval) < 0 || (yyval.lval) >= 16) print("register value out of range\n"); @@ -2527,9 +2440,8 @@ yyreduce: break; case 94: - -/* Line 1806 of yacc.c */ -#line 579 "a.y" +/* Line 1787 of yacc.c */ +#line 577 "a.y" { if((yyval.lval) < 0 || (yyval.lval) >= 32) print("shift value out of range\n"); @@ -2538,18 +2450,16 @@ yyreduce: break; case 96: - -/* Line 1806 of yacc.c */ -#line 588 "a.y" +/* Line 1787 of yacc.c */ +#line 586 "a.y" { (yyval.lval) = REGPC; } break; case 97: - -/* Line 1806 of yacc.c */ -#line 592 "a.y" +/* Line 1787 of yacc.c */ +#line 590 "a.y" { if((yyvsp[(3) - (4)].lval) < 0 || (yyvsp[(3) - (4)].lval) >= NREG) print("register value out of range\n"); @@ -2558,18 +2468,16 @@ yyreduce: break; case 99: - -/* Line 1806 of yacc.c */ -#line 601 "a.y" +/* Line 1787 of yacc.c */ +#line 599 "a.y" { (yyval.lval) = REGSP; } break; case 101: - -/* Line 1806 of yacc.c */ -#line 608 "a.y" +/* Line 1787 of yacc.c */ +#line 606 "a.y" { if((yyvsp[(3) - (4)].lval) < 0 || (yyvsp[(3) - (4)].lval) >= NREG) print("register value out of range\n"); @@ -2578,250 +2486,224 @@ yyreduce: break; case 104: - -/* Line 1806 of yacc.c */ -#line 620 "a.y" +/* Line 1787 of yacc.c */ +#line 618 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_FREG; - (yyval.gen).reg = (yyvsp[(1) - (1)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_FREG; + (yyval.addr).reg = (yyvsp[(1) - (1)].lval); } break; case 105: - -/* Line 1806 of yacc.c */ -#line 626 "a.y" +/* Line 1787 of yacc.c */ +#line 624 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_FREG; - (yyval.gen).reg = (yyvsp[(3) - (4)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_FREG; + (yyval.addr).reg = (yyvsp[(3) - (4)].lval); } break; case 106: - -/* Line 1806 of yacc.c */ -#line 634 "a.y" +/* Line 1787 of yacc.c */ +#line 632 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_OREG; - (yyval.gen).name = (yyvsp[(3) - (4)].lval); - (yyval.gen).sym = S; - (yyval.gen).offset = (yyvsp[(1) - (4)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_OREG; + (yyval.addr).name = (yyvsp[(3) - (4)].lval); + (yyval.addr).sym = nil; + (yyval.addr).offset = (yyvsp[(1) - (4)].lval); } break; case 107: - -/* Line 1806 of yacc.c */ -#line 642 "a.y" +/* Line 1787 of yacc.c */ +#line 640 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_OREG; - (yyval.gen).name = (yyvsp[(4) - (5)].lval); - (yyval.gen).sym = (yyvsp[(1) - (5)].sym); - (yyval.gen).offset = (yyvsp[(2) - (5)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_OREG; + (yyval.addr).name = (yyvsp[(4) - (5)].lval); + (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (5)].sym)->name, 0); + (yyval.addr).offset = (yyvsp[(2) - (5)].lval); } break; case 108: - -/* Line 1806 of yacc.c */ -#line 650 "a.y" +/* Line 1787 of yacc.c */ +#line 648 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_OREG; - (yyval.gen).name = D_STATIC; - (yyval.gen).sym = (yyvsp[(1) - (7)].sym); - (yyval.gen).offset = (yyvsp[(4) - (7)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_OREG; + (yyval.addr).name = D_STATIC; + (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (7)].sym)->name, 1); + (yyval.addr).offset = (yyvsp[(4) - (7)].lval); } break; case 109: - -/* Line 1806 of yacc.c */ -#line 659 "a.y" +/* Line 1787 of yacc.c */ +#line 657 "a.y" { (yyval.lval) = 0; } break; case 110: - -/* Line 1806 of yacc.c */ -#line 663 "a.y" +/* Line 1787 of yacc.c */ +#line 661 "a.y" { (yyval.lval) = (yyvsp[(2) - (2)].lval); } break; case 111: - -/* Line 1806 of yacc.c */ -#line 667 "a.y" +/* Line 1787 of yacc.c */ +#line 665 "a.y" { (yyval.lval) = -(yyvsp[(2) - (2)].lval); } break; case 116: - -/* Line 1806 of yacc.c */ -#line 679 "a.y" +/* Line 1787 of yacc.c */ +#line 677 "a.y" { (yyval.lval) = (yyvsp[(1) - (1)].sym)->value; } break; case 117: - -/* Line 1806 of yacc.c */ -#line 683 "a.y" +/* Line 1787 of yacc.c */ +#line 681 "a.y" { (yyval.lval) = -(yyvsp[(2) - (2)].lval); } break; case 118: - -/* Line 1806 of yacc.c */ -#line 687 "a.y" +/* Line 1787 of yacc.c */ +#line 685 "a.y" { (yyval.lval) = (yyvsp[(2) - (2)].lval); } break; case 119: - -/* Line 1806 of yacc.c */ -#line 691 "a.y" +/* Line 1787 of yacc.c */ +#line 689 "a.y" { (yyval.lval) = ~(yyvsp[(2) - (2)].lval); } break; case 120: - -/* Line 1806 of yacc.c */ -#line 695 "a.y" +/* Line 1787 of yacc.c */ +#line 693 "a.y" { (yyval.lval) = (yyvsp[(2) - (3)].lval); } break; case 121: - -/* Line 1806 of yacc.c */ -#line 700 "a.y" +/* Line 1787 of yacc.c */ +#line 698 "a.y" { (yyval.lval) = 0; } break; case 122: - -/* Line 1806 of yacc.c */ -#line 704 "a.y" +/* Line 1787 of yacc.c */ +#line 702 "a.y" { (yyval.lval) = (yyvsp[(2) - (2)].lval); } break; case 124: - -/* Line 1806 of yacc.c */ -#line 711 "a.y" +/* Line 1787 of yacc.c */ +#line 709 "a.y" { (yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval); } break; case 125: - -/* Line 1806 of yacc.c */ -#line 715 "a.y" +/* Line 1787 of yacc.c */ +#line 713 "a.y" { (yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval); } break; case 126: - -/* Line 1806 of yacc.c */ -#line 719 "a.y" +/* Line 1787 of yacc.c */ +#line 717 "a.y" { (yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval); } break; case 127: - -/* Line 1806 of yacc.c */ -#line 723 "a.y" +/* Line 1787 of yacc.c */ +#line 721 "a.y" { (yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval); } break; case 128: - -/* Line 1806 of yacc.c */ -#line 727 "a.y" +/* Line 1787 of yacc.c */ +#line 725 "a.y" { (yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval); } break; case 129: - -/* Line 1806 of yacc.c */ -#line 731 "a.y" +/* Line 1787 of yacc.c */ +#line 729 "a.y" { (yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval); } break; case 130: - -/* Line 1806 of yacc.c */ -#line 735 "a.y" +/* Line 1787 of yacc.c */ +#line 733 "a.y" { (yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval); } break; case 131: - -/* Line 1806 of yacc.c */ -#line 739 "a.y" +/* Line 1787 of yacc.c */ +#line 737 "a.y" { (yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval); } break; case 132: - -/* Line 1806 of yacc.c */ -#line 743 "a.y" +/* Line 1787 of yacc.c */ +#line 741 "a.y" { (yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval); } break; case 133: - -/* Line 1806 of yacc.c */ -#line 747 "a.y" +/* Line 1787 of yacc.c */ +#line 745 "a.y" { (yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval); } break; - -/* Line 1806 of yacc.c */ -#line 2825 "y.tab.c" +/* Line 1787 of yacc.c */ +#line 2707 "y.tab.c" default: break; } /* User semantic actions sometimes alter yychar, and that requires @@ -2984,7 +2866,9 @@ yyerrlab1: YY_STACK_PRINT (yyss, yyssp); } + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END /* Shift the error token. */ @@ -3008,7 +2892,7 @@ yyabortlab: yyresult = 1; goto yyreturn; -#if !defined(yyoverflow) || YYERROR_VERBOSE +#if !defined yyoverflow || YYERROR_VERBOSE /*-------------------------------------------------. | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ @@ -3050,4 +2934,3 @@ yyreturn: } - diff --git a/src/cmd/5a/y.tab.h b/src/cmd/5a/y.tab.h index 92230a2a5..f11fb85c6 100644 --- a/src/cmd/5a/y.tab.h +++ b/src/cmd/5a/y.tab.h @@ -1,8 +1,8 @@ -/* A Bison parser, made by GNU Bison 2.5. */ +/* A Bison parser, made by GNU Bison 2.7.12-4996. */ /* Bison interface for Yacc-like parsers in C - Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc. + Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -30,6 +30,15 @@ This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ +#ifndef YY_YY_Y_TAB_H_INCLUDED +# define YY_YY_Y_TAB_H_INCLUDED +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int yydebug; +#endif /* Tokens. */ #ifndef YYTOKENTYPE @@ -139,24 +148,21 @@ - #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE { - -/* Line 2068 of yacc.c */ +/* Line 2053 of yacc.c */ #line 39 "a.y" Sym *sym; int32 lval; double dval; char sval[8]; - Gen gen; + Addr addr; - -/* Line 2068 of yacc.c */ -#line 160 "y.tab.h" +/* Line 2053 of yacc.c */ +#line 166 "y.tab.h" } YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define yystype YYSTYPE /* obsolescent; will be withdrawn */ @@ -165,4 +171,18 @@ typedef union YYSTYPE extern YYSTYPE yylval; +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ +#endif /* !YY_YY_Y_TAB_H_INCLUDED */ diff --git a/src/cmd/5c/gc.h b/src/cmd/5c/gc.h index 084da7e6a..40d3a2b07 100644 --- a/src/cmd/5c/gc.h +++ b/src/cmd/5c/gc.h @@ -46,46 +46,19 @@ #define SZ_DOUBLE 8 #define FNX 100 -typedef struct Adr Adr; -typedef struct Prog Prog; typedef struct Case Case; typedef struct C1 C1; typedef struct Multab Multab; typedef struct Hintab Hintab; -typedef struct Var Var; typedef struct Reg Reg; typedef struct Rgn Rgn; #define R0ISZERO 0 -struct Adr -{ - int32 offset; - int32 offset2; - double dval; - char sval[NSNAME]; - Ieee ieee; - - Sym* sym; - char type; - uchar reg; - char name; - char etype; -}; -#define A ((Adr*)0) +#define A ((Addr*)0) #define INDEXED 9 -struct Prog -{ - Adr from; - Adr to; - Prog* link; - int32 lineno; - char as; - uchar reg; - uchar scond; -}; #define P ((Prog*)0) struct Case @@ -116,14 +89,6 @@ struct Hintab char hint[10]; }; -struct Var -{ - int32 offset; - Sym* sym; - char name; - char etype; -}; - struct Reg { int32 pc; @@ -174,7 +139,6 @@ EXTERN Node fconstnode; EXTERN int32 continpc; EXTERN int32 curarg; EXTERN int32 cursafe; -EXTERN Prog* firstp; EXTERN int32 isbigendian; EXTERN Prog* lastp; EXTERN int32 maxargsafe; @@ -230,7 +194,6 @@ EXTERN Reg* firstr; EXTERN Reg* lastr; EXTERN Reg zreg; EXTERN Reg* freer; -EXTERN Var var[NVAR]; EXTERN int32* idom; EXTERN Reg** rpo2r; EXTERN int32 maxnr; @@ -285,7 +248,7 @@ void regaalloc(Node*, Node*); void regind(Node*, Node*); void gprep(Node*, Node*); void raddr(Node*, Prog*); -void naddr(Node*, Adr*); +void naddr(Node*, Addr*); void gmovm(Node*, Node*, int); void gmove(Node*, Node*); void gmover(Node*, Node*); @@ -314,19 +277,11 @@ int mulcon(Node*, Node*); Multab* mulcon0(int32); void nullwarn(Node*, Node*); void outcode(void); -void ieeedtod(Ieee*, double); /* * list */ void listinit(void); -int Pconv(Fmt*); -int Aconv(Fmt*); -int Dconv(Fmt*); -int Sconv(Fmt*); -int Nconv(Fmt*); -int Bconv(Fmt*); -int Rconv(Fmt*); /* * reg.c @@ -335,7 +290,7 @@ Reg* rega(void); int rcmp(const void*, const void*); void regopt(Prog*); void addmove(Reg*, int, int, int); -Bits mkvar(Adr*, int); +Bits mkvar(Addr*, int); void prop(Reg*, Bits, Bits); void loopit(Reg*, int32); void synch(Reg*, Bits); @@ -343,7 +298,7 @@ uint32 allreg(uint32, Rgn*); void paint1(Reg*, int); uint32 paint2(Reg*, int); void paint3(Reg*, int, int32, int); -void addreg(Adr*, int); +void addreg(Addr*, int); /* * peep.c @@ -352,21 +307,21 @@ void peep(void); void excise(Reg*); Reg* uniqp(Reg*); Reg* uniqs(Reg*); -int regtyp(Adr*); -int regzer(Adr*); -int anyvar(Adr*); +int regtyp(Addr*); +int regzer(Addr*); +int anyvar(Addr*); int subprop(Reg*); int copyprop(Reg*); int shiftprop(Reg*); -void constprop(Adr*, Adr*, Reg*); -int copy1(Adr*, Adr*, Reg*, int); -int copyu(Prog*, Adr*, Adr*); +void constprop(Addr*, Addr*, Reg*); +int copy1(Addr*, Addr*, Reg*, int); +int copyu(Prog*, Addr*, Addr*); -int copyas(Adr*, Adr*); -int copyau(Adr*, Adr*); -int copyau1(Prog*, Adr*); -int copysub(Adr*, Adr*, Adr*, int); -int copysub1(Prog*, Adr*, Adr*, int); +int copyas(Addr*, Addr*); +int copyau(Addr*, Addr*); +int copyau1(Prog*, Addr*); +int copysub(Addr*, Addr*, Addr*, int); +int copysub1(Prog*, Addr*, Addr*, int); int32 RtoB(int); int32 FtoB(int); @@ -377,11 +332,3 @@ void predicate(void); int isbranch(Prog *); int predicable(Prog *p); int modifiescpsr(Prog *p); - -#pragma varargck type "A" int -#pragma varargck type "B" Bits -#pragma varargck type "D" Adr* -#pragma varargck type "N" Adr* -#pragma varargck type "R" Adr* -#pragma varargck type "P" Prog* -#pragma varargck type "S" char* diff --git a/src/cmd/5c/list.c b/src/cmd/5c/list.c index 30b88400f..98da424de 100644 --- a/src/cmd/5c/list.c +++ b/src/cmd/5c/list.c @@ -35,306 +35,5 @@ void listinit(void) { - - fmtinstall('A', Aconv); - fmtinstall('P', Pconv); - fmtinstall('S', Sconv); - fmtinstall('N', Nconv); - fmtinstall('B', Bconv); - fmtinstall('D', Dconv); - fmtinstall('R', Rconv); -} - -int -Bconv(Fmt *fp) -{ - char str[STRINGSZ], ss[STRINGSZ], *s; - Bits bits; - int i; - - str[0] = 0; - bits = va_arg(fp->args, Bits); - while(bany(&bits)) { - i = bnum(bits); - if(str[0]) - strcat(str, " "); - if(var[i].sym == S) { - sprint(ss, "$%d", var[i].offset); - s = ss; - } else - s = var[i].sym->name; - if(strlen(str) + strlen(s) + 1 >= STRINGSZ) - break; - strcat(str, s); - bits.b[i/32] &= ~(1L << (i%32)); - } - return fmtstrcpy(fp, str); -} - -char *extra [] = { - ".EQ", ".NE", ".CS", ".CC", - ".MI", ".PL", ".VS", ".VC", - ".HI", ".LS", ".GE", ".LT", - ".GT", ".LE", "", ".NV", -}; - -int -Pconv(Fmt *fp) -{ - char str[STRINGSZ], sc[20]; - Prog *p; - int a, s; - - p = va_arg(fp->args, Prog*); - a = p->as; - s = p->scond; - strcpy(sc, extra[s & C_SCOND]); - if(s & C_SBIT) - strcat(sc, ".S"); - if(s & C_PBIT) - strcat(sc, ".P"); - if(s & C_WBIT) - strcat(sc, ".W"); - if(s & C_UBIT) /* ambiguous with FBIT */ - strcat(sc, ".U"); - if(a == AMOVM) { - if(p->from.type == D_CONST) - sprint(str, " %A%s %R,%D", a, sc, &p->from, &p->to); - else - if(p->to.type == D_CONST) - sprint(str, " %A%s %D,%R", a, sc, &p->from, &p->to); - else - sprint(str, " %A%s %D,%D", a, sc, &p->from, &p->to); - } else - if(a == ADATA) - sprint(str, " %A %D/%d,%D", a, &p->from, p->reg, &p->to); - else - if(p->as == ATEXT) - sprint(str, " %A %D,%d,%D", a, &p->from, p->reg, &p->to); - else - if(p->reg == NREG) - sprint(str, " %A%s %D,%D", a, sc, &p->from, &p->to); - else - if(p->from.type != D_FREG) - sprint(str, " %A%s %D,R%d,%D", a, sc, &p->from, p->reg, &p->to); - else - sprint(str, " %A%s %D,F%d,%D", a, sc, &p->from, p->reg, &p->to); - return fmtstrcpy(fp, str); -} - -int -Aconv(Fmt *fp) -{ - char *s; - int a; - - a = va_arg(fp->args, int); - s = "???"; - if(a >= AXXX && a < ALAST) - s = anames[a]; - return fmtstrcpy(fp, s); -} - -int -Dconv(Fmt *fp) -{ - char str[STRINGSZ]; - Adr *a; - const char *op; - int v; - - a = va_arg(fp->args, Adr*); - switch(a->type) { - - default: - sprint(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); - break; - - case D_CONST: - if(a->reg != NREG) - sprint(str, "$%N(R%d)", a, a->reg); - else - sprint(str, "$%N", a); - break; - - case D_CONST2: - sprint(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); - else - sprint(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); - break; - - case D_OREG: - if(a->reg != NREG) - sprint(str, "%N(R%d)", a, a->reg); - else - sprint(str, "%N", a); - break; - - case D_REG: - sprint(str, "R%d", a->reg); - if(a->name != D_NONE || a->sym != S) - sprint(str, "%N(R%d)(REG)", a, a->reg); - break; - - case D_FREG: - sprint(str, "F%d", a->reg); - if(a->name != D_NONE || a->sym != S) - sprint(str, "%N(R%d)(REG)", a, a->reg); - break; - - case D_PSR: - sprint(str, "PSR"); - if(a->name != D_NONE || a->sym != S) - sprint(str, "%N(PSR)(REG)", a); - break; - - case D_BRANCH: - sprint(str, "%d(PC)", a->offset-pc); - break; - - case D_FCONST: - sprint(str, "$%.17e", a->dval); - break; - - case D_SCONST: - sprint(str, "$\"%S\"", a->sval); - break; - } - return fmtstrcpy(fp, str); -} - -int -Rconv(Fmt *fp) -{ - char str[STRINGSZ]; - Adr *a; - int i, v; - - a = va_arg(fp->args, Adr*); - sprint(str, "GOK-reglist"); - switch(a->type) { - case D_CONST: - case D_CONST2: - if(a->reg != NREG) - break; - if(a->sym != S) - break; - v = a->offset; - strcpy(str, ""); - for(i=0; iargs, char*); - p = str; - for(i=0; i= 'a' && c <= 'z' || - c >= 'A' && c <= 'Z' || - c >= '0' && c <= '9' || - c == ' ' || c == '%') { - *p++ = c; - continue; - } - *p++ = '\\'; - switch(c) { - case 0: - *p++ = 'z'; - continue; - case '\\': - case '"': - *p++ = c; - continue; - case '\n': - *p++ = 'n'; - continue; - case '\t': - *p++ = 't'; - continue; - case '\r': - *p++ = 'r'; - continue; - case '\f': - *p++ = 'f'; - continue; - } - *p++ = (c>>6) + '0'; - *p++ = ((c>>3) & 7) + '0'; - *p++ = (c & 7) + '0'; - } - *p = 0; - return fmtstrcpy(fp, str); -} - -int -Nconv(Fmt *fp) -{ - char str[STRINGSZ]; - Adr *a; - Sym *s; - - a = va_arg(fp->args, Adr*); - s = a->sym; - if(s == S) { - sprint(str, "%d", a->offset); - goto out; - } - switch(a->name) { - default: - sprint(str, "GOK-name(%d)", a->name); - break; - - case D_NONE: - sprint(str, "%d", a->offset); - break; - - case D_EXTERN: - sprint(str, "%s+%d(SB)", s->name, a->offset); - break; - - case D_STATIC: - sprint(str, "%s<>+%d(SB)", s->name, a->offset); - break; - - case D_AUTO: - sprint(str, "%s-%d(SP)", s->name, -a->offset); - break; - - case D_PARAM: - sprint(str, "%s+%d(FP)", s->name, a->offset); - break; - } -out: - return fmtstrcpy(fp, str); + listinit5(); } diff --git a/src/cmd/5c/peep.c b/src/cmd/5c/peep.c index 22328c18c..143400a63 100644 --- a/src/cmd/5c/peep.c +++ b/src/cmd/5c/peep.c @@ -31,7 +31,7 @@ #include "gc.h" -int xtramodes(Reg*, Adr*); +int xtramodes(Reg*, Addr*); void peep(void) @@ -281,7 +281,7 @@ uniqs(Reg *r) } int -regtyp(Adr *a) +regtyp(Addr *a) { if(a->type == D_REG) @@ -309,7 +309,7 @@ int subprop(Reg *r0) { Prog *p; - Adr *v1, *v2; + Addr *v1, *v2; Reg *r; int t; @@ -427,7 +427,7 @@ int copyprop(Reg *r0) { Prog *p; - Adr *v1, *v2; + Addr *v1, *v2; Reg *r; p = r0->prog; @@ -441,7 +441,7 @@ copyprop(Reg *r0) } int -copy1(Adr *v1, Adr *v2, Reg *r, int f) +copy1(Addr *v1, Addr *v2, Reg *r, int f) { int t; Prog *p; @@ -525,7 +525,7 @@ copy1(Adr *v1, Adr *v2, Reg *r, int f) * The v1->v2 should be eliminated by copy propagation. */ void -constprop(Adr *c1, Adr *v1, Reg *r) +constprop(Addr *c1, Addr *v1, Reg *r) { Prog *p; @@ -574,7 +574,7 @@ shiftprop(Reg *r) Reg *r1; Prog *p, *p1, *p2; int n, o; - Adr a; + Addr a; p = r->prog; if(p->to.type != D_REG) @@ -710,7 +710,7 @@ shiftprop(Reg *r) } Reg* -findpre(Reg *r, Adr *v) +findpre(Reg *r, Addr *v) { Reg *r1; @@ -730,7 +730,7 @@ findpre(Reg *r, Adr *v) } Reg* -findinc(Reg *r, Reg *r2, Adr *v) +findinc(Reg *r, Reg *r2, Addr *v) { Reg *r1; Prog *p; @@ -758,7 +758,7 @@ findinc(Reg *r, Reg *r2, Adr *v) int nochange(Reg *r, Reg *r2, Prog *p) { - Adr a[3]; + Addr a[3]; int i, n; if(r == r2) @@ -788,7 +788,7 @@ nochange(Reg *r, Reg *r2, Prog *p) } int -findu1(Reg *r, Adr *v) +findu1(Reg *r, Addr *v) { for(; r != R; r = r->s1) { if(r->active) @@ -810,7 +810,7 @@ findu1(Reg *r, Adr *v) } int -finduse(Reg *r, Adr *v) +finduse(Reg *r, Addr *v) { Reg *r1; @@ -820,11 +820,11 @@ finduse(Reg *r, Adr *v) } int -xtramodes(Reg *r, Adr *a) +xtramodes(Reg *r, Addr *a) { Reg *r1, *r2, *r3; Prog *p, *p1; - Adr v; + Addr v; p = r->prog; if((p->as == AMOVB || p->as == AMOVBS) && p->from.type == D_OREG) /* byte load */ @@ -911,7 +911,7 @@ xtramodes(Reg *r, Adr *a) * 0 otherwise (not touched) */ int -copyu(Prog *p, Adr *v, Adr *s) +copyu(Prog *p, Addr *v, Addr *s) { switch(p->as) { @@ -1106,7 +1106,7 @@ copyu(Prog *p, Adr *v, Adr *s) if(v->type == D_REG) { if(v->reg <= REGEXT && v->reg > exregoffset) return 2; - if(v->reg == (uchar)REGARG) + if(v->reg == REGARG) return 2; } if(v->type == D_FREG) @@ -1124,7 +1124,7 @@ copyu(Prog *p, Adr *v, Adr *s) case ATEXT: /* funny */ if(v->type == D_REG) - if(v->reg == (uchar)REGARG) + if(v->reg == REGARG) return 3; return 0; } @@ -1175,7 +1175,7 @@ a2type(Prog *p) * semantics */ int -copyas(Adr *a, Adr *v) +copyas(Addr *a, Addr *v) { if(regtyp(v)) { @@ -1197,7 +1197,7 @@ copyas(Adr *a, Adr *v) * either direct or indirect */ int -copyau(Adr *a, Adr *v) +copyau(Addr *a, Addr *v) { if(copyas(a, v)) @@ -1217,7 +1217,7 @@ copyau(Adr *a, Adr *v) } int -copyau1(Prog *p, Adr *v) +copyau1(Prog *p, Addr *v) { if(regtyp(v)) { @@ -1236,7 +1236,7 @@ copyau1(Prog *p, Adr *v) * return failure to substitute */ int -copysub(Adr *a, Adr *v, Adr *s, int f) +copysub(Addr *a, Addr *v, Addr *s, int f) { if(f) @@ -1253,7 +1253,7 @@ copysub(Adr *a, Adr *v, Adr *s, int f) } int -copysub1(Prog *p1, Adr *v, Adr *s, int f) +copysub1(Prog *p1, Addr *v, Addr *s, int f) { if(f) diff --git a/src/cmd/5c/reg.c b/src/cmd/5c/reg.c index 3d67872b4..b9ac21abd 100644 --- a/src/cmd/5c/reg.c +++ b/src/cmd/5c/reg.c @@ -480,8 +480,10 @@ brk: r1 = 0; /* set */ for(r = firstr; r != R; r = r->link) { p = r->prog; - if(p->to.type == D_BRANCH) + if(p->to.type == D_BRANCH) { p->to.offset = r->s2->pc; + p->to.u.branch = r->s2->prog; + } r1 = r; } @@ -535,7 +537,7 @@ void addmove(Reg *r, int bn, int rn, int f) { Prog *p, *p1; - Adr *a; + Addr *a; Var *v; p1 = alloc(sizeof(*p1)); @@ -554,7 +556,7 @@ addmove(Reg *r, int bn, int rn, int f) a->offset = v->offset; a->etype = v->etype; a->type = D_OREG; - if(a->etype == TARRAY || a->sym == S) + if(a->etype == TARRAY || a->sym == nil) a->type = D_CONST; p1->as = AMOVW; @@ -592,13 +594,13 @@ addmove(Reg *r, int bn, int rn, int f) } Bits -mkvar(Adr *a, int docon) +mkvar(Addr *a, int docon) { Var *v; int i, t, n, et, z; int32 o; Bits bit; - Sym *s; + LSym *s; t = a->type; if(t == D_REG && a->reg != NREG) @@ -608,13 +610,13 @@ mkvar(Adr *a, int docon) s = a->sym; o = a->offset; et = a->etype; - if(s == S) { + if(s == nil) { if(t != D_CONST || !docon || a->reg != NREG) goto none; et = TLONG; } if(t == D_CONST) { - if(s == S && sval(o)) + if(s == nil && sval(o)) goto none; } @@ -656,7 +658,7 @@ out: for(z=0; zsym = 0; diff --git a/src/cmd/5c/swt.c b/src/cmd/5c/swt.c index 0f0c457f8..fd81a4e68 100644 --- a/src/cmd/5c/swt.c +++ b/src/cmd/5c/swt.c @@ -206,7 +206,7 @@ outstring(char *s, int32 n) p->from.offset += nstring - NSNAME; p->reg = NSNAME; p->to.type = D_SCONST; - memmove(p->to.sval, string, NSNAME); + memmove(p->to.u.sval, string, NSNAME); mnstring = 0; } n--; @@ -321,7 +321,7 @@ sextern(Sym *s, Node *a, int32 o, int32 w) p->from.offset += o+e; p->reg = lw; p->to.type = D_SCONST; - memmove(p->to.sval, a->cstring+e, lw); + memmove(p->to.u.sval, a->cstring+e, lw); } } @@ -351,48 +351,10 @@ gextern(Sym *s, Node *a, int32 o, int32 w) p->to.type = D_CONST; } -void zname(Biobuf*, Sym*, int); -char* zaddr(char*, Adr*, int); -void zwrite(Biobuf*, Prog*, int, int); -void outhist(Biobuf*); - -void -zwrite(Biobuf *b, Prog *p, int sf, int st) -{ - char bf[100], *bp; - - bf[0] = p->as; - bf[1] = p->scond; - bf[2] = p->reg; - bf[3] = p->lineno; - bf[4] = p->lineno>>8; - bf[5] = p->lineno>>16; - bf[6] = p->lineno>>24; - bp = zaddr(bf+7, &p->from, sf); - bp = zaddr(bp, &p->to, st); - Bwrite(b, bf, bp-bf); -} - void outcode(void) { - struct { Sym *sym; short type; } h[NSYM]; - Prog *p; - Sym *s; - int sf, st, t, sym; - - if(debug['S']) { - for(p = firstp; p != P; p = p->link) - if(p->as != ADATA && p->as != AGLOBL) - pc--; - for(p = firstp; p != P; p = p->link) { - print("%P\n", p); - if(p->as != ADATA && p->as != AGLOBL) - pc++; - } - } - - Bprint(&outbuf, "go object %s %s %s\n", getgoos(), thestring, getgoversion()); + Bprint(&outbuf, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion()); if(pragcgobuf.to > pragcgobuf.start) { Bprint(&outbuf, "\n"); Bprint(&outbuf, "$$ // exports\n\n"); @@ -403,249 +365,10 @@ outcode(void) } Bprint(&outbuf, "!\n"); - outhist(&outbuf); - for(sym=0; symlink) { - jackpot: - sf = 0; - s = p->from.sym; - while(s != S) { - sf = s->sym; - if(sf < 0 || sf >= NSYM) - sf = 0; - t = p->from.name; - if(h[sf].type == t) - if(h[sf].sym == s) - break; - s->sym = sym; - zname(&outbuf, s, t); - h[sym].sym = s; - h[sym].type = t; - sf = sym; - sym++; - if(sym >= NSYM) - sym = 1; - break; - } - st = 0; - s = p->to.sym; - while(s != S) { - st = s->sym; - if(st < 0 || st >= NSYM) - st = 0; - t = p->to.name; - if(h[st].type == t) - if(h[st].sym == s) - break; - s->sym = sym; - zname(&outbuf, s, t); - h[sym].sym = s; - h[sym].type = t; - st = sym; - sym++; - if(sym >= NSYM) - sym = 1; - if(st == sf) - goto jackpot; - break; - } - zwrite(&outbuf, p, sf, st); - } - firstp = P; + writeobj(ctxt, &outbuf); lastp = P; } -void -outhist(Biobuf *b) -{ - Hist *h; - char *p, *q, *op, c; - Prog pg; - int n; - char *tofree; - static int first = 1; - static char *goroot, *goroot_final; - - if(first) { - // Decide whether we need to rewrite paths from $GOROOT to $GOROOT_FINAL. - first = 0; - goroot = getenv("GOROOT"); - goroot_final = getenv("GOROOT_FINAL"); - if(goroot == nil) - goroot = ""; - if(goroot_final == nil) - goroot_final = goroot; - if(strcmp(goroot, goroot_final) == 0) { - goroot = nil; - goroot_final = nil; - } - } - - tofree = nil; - pg = zprog; - pg.as = AHISTORY; - c = pathchar(); - for(h = hist; h != H; h = h->link) { - p = h->name; - if(p != nil && goroot != nil) { - n = strlen(goroot); - if(strncmp(p, goroot, strlen(goroot)) == 0 && p[n] == '/') { - tofree = smprint("%s%s", goroot_final, p+n); - p = tofree; - } - } - op = 0; - if(systemtype(Windows) && p && p[1] == ':'){ - c = p[2]; - } else if(p && p[0] != c && h->offset == 0 && pathname){ - if(systemtype(Windows) && pathname[1] == ':') { - op = p; - p = pathname; - c = p[2]; - } else if(pathname[0] == c){ - op = p; - p = pathname; - } - } - while(p) { - q = utfrune(p, c); - if(q) { - n = q-p; - if(n == 0){ - n = 1; /* leading "/" */ - *p = '/'; /* don't emit "\" on windows */ - } - q++; - } else { - n = strlen(p); - q = 0; - } - if(n) { - BPUTC(b, ANAME); - BPUTC(b, D_FILE); - BPUTC(b, 1); - BPUTC(b, '<'); - Bwrite(b, p, n); - BPUTC(b, 0); - } - p = q; - if(p == 0 && op) { - p = op; - op = 0; - } - } - pg.lineno = h->line; - pg.to.type = zprog.to.type; - pg.to.offset = h->offset; - if(h->offset) - pg.to.type = D_CONST; - - zwrite(b, &pg, 0, 0); - - if(tofree) { - free(tofree); - tofree = nil; - } - } -} - -void -zname(Biobuf *b, Sym *s, int t) -{ - char *n, bf[7]; - uint32 sig; - - n = s->name; - if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){ - sig = sign(s); - bf[0] = ASIGNAME; - bf[1] = sig; - bf[2] = sig>>8; - bf[3] = sig>>16; - bf[4] = sig>>24; - bf[5] = t; - bf[6] = s->sym; - Bwrite(b, bf, 7); - s->sig = SIGDONE; - } - else{ - bf[0] = ANAME; - bf[1] = t; /* type */ - bf[2] = s->sym; /* sym */ - Bwrite(b, bf, 3); - } - Bwrite(b, n, strlen(n)+1); -} - -char* -zaddr(char *bp, Adr *a, int s) -{ - int32 l; - Ieee e; - - bp[0] = a->type; - bp[1] = a->reg; - bp[2] = s; - bp[3] = a->name; - bp[4] = 0; - bp += 5; - switch(a->type) { - default: - diag(Z, "unknown type %d in zaddr", a->type); - - case D_NONE: - case D_REG: - case D_FREG: - case D_PSR: - break; - - case D_CONST2: - l = a->offset2; - bp[0] = l; - bp[1] = l>>8; - bp[2] = l>>16; - bp[3] = l>>24; - bp += 4; // fall through - case D_OREG: - case D_CONST: - case D_BRANCH: - case D_SHIFT: - l = a->offset; - bp[0] = l; - bp[1] = l>>8; - bp[2] = l>>16; - bp[3] = l>>24; - bp += 4; - break; - - case D_SCONST: - memmove(bp, a->sval, NSNAME); - bp += NSNAME; - break; - - case D_FCONST: - ieeedtod(&e, a->dval); - l = e.l; - bp[0] = l; - bp[1] = l>>8; - bp[2] = l>>16; - bp[3] = l>>24; - bp += 4; - l = e.h; - bp[0] = l; - bp[1] = l>>8; - bp[2] = l>>16; - bp[3] = l>>24; - bp += 4; - break; - } - return bp; -} - int32 align(int32 i, Type *t, int op, int32 *maxalign) { diff --git a/src/cmd/5c/txt.c b/src/cmd/5c/txt.c index 6d9b69d00..a753510ca 100644 --- a/src/cmd/5c/txt.c +++ b/src/cmd/5c/txt.c @@ -31,13 +31,22 @@ #include "gc.h" + +int thechar = '5'; +char *thestring = "arm"; + +LinkArch *thelinkarch = &linkarm; + +void +linkarchinit(void) +{ +} + void ginit(void) { Type *t; - thechar = '5'; - thestring = "arm"; exregoffset = REGEXT; exfregoffset = FREGEXT; listinit(); @@ -48,7 +57,6 @@ ginit(void) breakpc = -1; continpc = -1; cases = C; - firstp = P; lastp = P; tfield = types[TLONG]; @@ -149,17 +157,17 @@ gclean(void) void nextpc(void) { + Plist *pl; p = alloc(sizeof(*p)); *p = zprog; p->lineno = nearln; pc++; - if(firstp == P) { - firstp = p; - lastp = p; - return; - } - lastp->link = p; + if(lastp == nil) { + pl = linknewplist(ctxt); + pl->firstpc = p; + } else + lastp->link = p; lastp = p; } @@ -422,7 +430,7 @@ regind(Node *n, Node *nn) void raddr(Node *n, Prog *p) { - Adr a; + Addr a; naddr(n, &a); if(R0ISZERO && a.type == D_CONST && a.offset == 0) { @@ -440,7 +448,7 @@ raddr(Node *n, Prog *p) } void -naddr(Node *n, Adr *a) +naddr(Node *n, Addr *a) { int32 v; @@ -455,7 +463,7 @@ naddr(Node *n, Adr *a) case OREGISTER: a->type = D_REG; - a->sym = S; + a->sym = nil; a->reg = n->reg; if(a->reg >= NREG) { a->type = D_FREG; @@ -477,7 +485,7 @@ naddr(Node *n, Adr *a) case OINDREG: a->type = D_OREG; - a->sym = S; + a->sym = nil; a->offset = n->xoffset; a->reg = n->reg; break; @@ -486,7 +494,7 @@ naddr(Node *n, Adr *a) a->etype = n->etype; a->type = D_OREG; a->name = D_STATIC; - a->sym = n->sym; + a->sym = linksym(n->sym); a->offset = n->xoffset; if(n->class == CSTATIC) break; @@ -505,11 +513,11 @@ naddr(Node *n, Adr *a) goto bad; case OCONST: - a->sym = S; + a->sym = nil; a->reg = NREG; if(typefd[n->type->etype]) { a->type = D_FCONST; - a->dval = n->fconst; + a->u.dval = n->fconst; } else { a->type = D_CONST; a->offset = n->vconst; @@ -930,7 +938,7 @@ void gopcode(int o, Node *f1, Node *f2, Node *t) { int a, et; - Adr ta; + Addr ta; et = TLONG; if(f1 != Z && f1->type != T) @@ -1177,7 +1185,7 @@ gpseudo(int a, Sym *s, Node *n) nextpc(); p->as = a; p->from.type = D_OREG; - p->from.sym = s; + p->from.sym = linksym(s); p->from.name = D_EXTERN; switch(a) { diff --git a/src/cmd/5g/cgen.c b/src/cmd/5g/cgen.c index 2d260e72d..9011b2022 100644 --- a/src/cmd/5g/cgen.c +++ b/src/cmd/5g/cgen.c @@ -254,6 +254,7 @@ cgen(Node *n, Node *res) case OOR: case OXOR: case OADD: + case OADDPTR: case OMUL: a = optoas(n->op, nl->type); goto sbop; @@ -604,6 +605,7 @@ agen(Node *n, Node *res) // The generated code is just going to panic, so it need not // be terribly efficient. See issue 3670. tempname(&n1, n->type); + gvardef(&n1); clearfat(&n1); regalloc(&n2, types[tptr], res); gins(AMOVW, &n1, &n2); @@ -1410,10 +1412,11 @@ stkof(Node *n) void sgen(Node *n, Node *res, int64 w) { - Node dst, src, tmp, nend; + Node dst, src, tmp, nend, r0, r1, r2, *f; int32 c, odst, osrc; int dir, align, op; Prog *p, *ploop; + NodeList *l; if(debug['g']) { print("\nsgen w=%lld\n", w); @@ -1439,6 +1442,13 @@ sgen(Node *n, Node *res, int64 w) return; } + // If copying .args, that's all the results, so record definition sites + // for them for the liveness analysis. + if(res->op == ONAME && strcmp(res->sym->name, ".args") == 0) + for(l = curfn->dcl; l != nil; l = l->next) + if(l->n->class == PPARAMOUT) + gvardef(l->n); + // Avoid taking the address for simple enough types. if(componentgen(n, res)) return; @@ -1480,18 +1490,59 @@ sgen(Node *n, Node *res, int64 w) } if(osrc%align != 0 || odst%align != 0) fatal("sgen: unaligned offset src %d or dst %d (align %d)", osrc, odst, align); + // if we are copying forward on the stack and // the src and dst overlap, then reverse direction dir = align; if(osrc < odst && odst < osrc+w) dir = -dir; + if(op == AMOVW && dir > 0 && c >= 4 && c <= 128) { + r0.op = OREGISTER; + r0.val.u.reg = REGALLOC_R0; + r1.op = OREGISTER; + r1.val.u.reg = REGALLOC_R0 + 1; + r2.op = OREGISTER; + r2.val.u.reg = REGALLOC_R0 + 2; + + regalloc(&src, types[tptr], &r1); + regalloc(&dst, types[tptr], &r2); + if(n->ullman >= res->ullman) { + // eval n first + agen(n, &src); + if(res->op == ONAME) + gvardef(res); + agen(res, &dst); + } else { + // eval res first + if(res->op == ONAME) + gvardef(res); + agen(res, &dst); + agen(n, &src); + } + regalloc(&tmp, types[tptr], &r0); + f = sysfunc("duffcopy"); + p = gins(ADUFFCOPY, N, f); + afunclit(&p->to, f); + // 8 and 128 = magic constants: see ../../pkg/runtime/asm_arm.s + p->to.offset = 8*(128-c); + + regfree(&tmp); + regfree(&src); + regfree(&dst); + return; + } + if(n->ullman >= res->ullman) { agenr(n, &dst, res); // temporarily use dst regalloc(&src, types[tptr], N); gins(AMOVW, &dst, &src); + if(res->op == ONAME) + gvardef(res); agen(res, &dst); } else { + if(res->op == ONAME) + gvardef(res); agenr(res, &dst, res); agenr(n, &src, N); } @@ -1624,8 +1675,17 @@ componentgen(Node *nr, Node *nl) freer = 1; } + // nl and nr are 'cadable' which basically means they are names (variables) now. + // If they are the same variable, don't generate any code, because the + // VARDEF we generate will mark the old value as dead incorrectly. + // (And also the assignments are useless.) + if(nr != N && nl->op == ONAME && nr->op == ONAME && nl == nr) + goto yes; + switch(nl->type->etype) { case TARRAY: + if(nl->op == ONAME) + gvardef(nl); nodl.xoffset += Array_array; nodl.type = ptrto(nl->type->type); @@ -1656,6 +1716,8 @@ componentgen(Node *nr, Node *nl) goto yes; case TSTRING: + if(nl->op == ONAME) + gvardef(nl); nodl.xoffset += Array_array; nodl.type = ptrto(types[TUINT8]); @@ -1677,6 +1739,8 @@ componentgen(Node *nr, Node *nl) goto yes; case TINTER: + if(nl->op == ONAME) + gvardef(nl); nodl.xoffset += Array_array; nodl.type = ptrto(types[TUINT8]); diff --git a/src/cmd/5g/galign.c b/src/cmd/5g/galign.c index 1fbf633f9..a62102ef8 100644 --- a/src/cmd/5g/galign.c +++ b/src/cmd/5g/galign.c @@ -8,6 +8,12 @@ int thechar = '5'; char* thestring = "arm"; +LinkArch* thelinkarch = &linkarm; + +void +linkarchinit(void) +{ +} vlong MAXWIDTH = (1LL<<32) - 1; @@ -28,6 +34,7 @@ betypeinit(void) { widthptr = 4; widthint = 4; + widthreg = 4; zprog.link = P; zprog.as = AGOK; @@ -38,5 +45,5 @@ betypeinit(void) zprog.from.reg = NREG; zprog.to = zprog.from; - listinit(); + listinit5(); } diff --git a/src/cmd/5g/gg.h b/src/cmd/5g/gg.h index 860817f69..413e93c24 100644 --- a/src/cmd/5g/gg.h +++ b/src/cmd/5g/gg.h @@ -9,44 +9,6 @@ #include "../gc/go.h" #include "../5l/5.out.h" -typedef struct Addr Addr; - -struct Addr -{ - int32 offset; - int32 offset2; - - union { - double dval; - vlong vval; - Prog* branch; - char sval[NSNAME]; - } u; - - Sym* sym; - Sym* gotype; - Node* node; - int width; - uchar type; - char name; - uchar reg; - uchar etype; -}; -#define A ((Addr*)0) - -struct Prog -{ - uint32 loc; // pc offset in this func - uint32 lineno; // source line that generated this - Prog* link; // next instruction in this func - void* opt; // for optimizer passes - short as; // opcode - uchar reg; // doubles as width in DATA op - uchar scond; - Addr from; // src address - Addr to; // dst address -}; - #define TEXTFLAG reg #define REGALLOC_R0 0 @@ -58,7 +20,6 @@ EXTERN int32 dynloc; EXTERN uchar reg[REGALLOC_FMAX+1]; EXTERN int32 pcloc; // instruction counter EXTERN Strlit emptystring; -extern char* anames[]; EXTERN Prog zprog; EXTERN Node* newproc; EXTERN Node* deferproc; @@ -67,7 +28,6 @@ EXTERN Node* panicindex; EXTERN Node* panicslice; EXTERN Node* throwreturn; extern long unmappedzero; -EXTERN int maxstksize; /* * gen.c @@ -156,16 +116,6 @@ void datastring(char*, int, Addr*); /* * list.c */ -int Aconv(Fmt*); -int Cconv(Fmt*); -int Dconv(Fmt*); -int Mconv(Fmt*); -int Pconv(Fmt*); -int Rconv(Fmt*); -int Yconv(Fmt*); void listinit(void); void zaddr(Biobuf*, Addr*, int, int); - -#pragma varargck type "D" Addr* -#pragma varargck type "M" Addr* diff --git a/src/cmd/5g/ggen.c b/src/cmd/5g/ggen.c index 040c3d2a9..fb32c2f36 100644 --- a/src/cmd/5g/ggen.c +++ b/src/cmd/5g/ggen.c @@ -9,78 +9,114 @@ #include "gg.h" #include "opt.h" -static Prog* appendp(Prog*, int, int, int, int32, int, int, int32); +static Prog* appendpp(Prog*, int, int, int, int32, int, int, int32); +static Prog *zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *r0); void -defframe(Prog *ptxt, Bvec *bv) +defframe(Prog *ptxt) { - int i, j, first; - uint32 frame; - Prog *p, *p1; - + uint32 frame, r0; + Prog *p; + vlong hi, lo; + NodeList *l; + Node *n; + // fill in argument size ptxt->to.type = D_CONST2; ptxt->to.offset2 = rnd(curfn->type->argwid, widthptr); // fill in final stack size - if(stksize > maxstksize) - maxstksize = stksize; - frame = rnd(maxstksize+maxarg, widthptr); + frame = rnd(stksize+maxarg, widthptr); ptxt->to.offset = frame; - maxstksize = 0; - - // insert code to clear pointered part of the frame, + + // insert code to contain ambiguously live variables // so that garbage collector only sees initialized values // when it looks for pointers. p = ptxt; - while(p->link->as == AFUNCDATA || p->link->as == APCDATA || p->link->as == ATYPE) - p = p->link; - if(stkzerosize >= 8*widthptr) { - p = appendp(p, AMOVW, D_CONST, NREG, 0, D_REG, 0, 0); - p = appendp(p, AADD, D_CONST, NREG, 4+frame-stkzerosize, D_REG, 1, 0); + lo = hi = 0; + r0 = 0; + for(l=curfn->dcl; l != nil; l = l->next) { + n = l->n; + if(!n->needzero) + continue; + if(n->class != PAUTO) + fatal("needzero class %d", n->class); + if(n->type->width % widthptr != 0 || n->xoffset % widthptr != 0 || n->type->width == 0) + fatal("var %lN has size %d offset %d", n, (int)n->type->width, (int)n->xoffset); + if(lo != hi && n->xoffset + n->type->width >= lo - 2*widthptr) { + // merge with range we already have + lo = rnd(n->xoffset, widthptr); + continue; + } + // zero old range + p = zerorange(p, frame, lo, hi, &r0); + + // set new range + hi = n->xoffset + n->type->width; + lo = n->xoffset; + } + // zero final range + zerorange(p, frame, lo, hi, &r0); +} + +static Prog* +zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *r0) +{ + vlong cnt, i; + Prog *p1; + Node *f; + + cnt = hi - lo; + if(cnt == 0) + return p; + if(*r0 == 0) { + p = appendpp(p, AMOVW, D_CONST, NREG, 0, D_REG, 0, 0); + *r0 = 1; + } + if(cnt < 4*widthptr) { + for(i = 0; i < cnt; i += widthptr) + p = appendpp(p, AMOVW, D_REG, 0, 0, D_OREG, REGSP, 4+frame+lo+i); + } else if(cnt <= 128*widthptr) { + p = appendpp(p, AADD, D_CONST, NREG, 4+frame+lo, D_REG, 1, 0); p->reg = REGSP; - p = appendp(p, AADD, D_CONST, NREG, stkzerosize, D_REG, 2, 0); + p = appendpp(p, ADUFFZERO, D_NONE, NREG, 0, D_OREG, NREG, 0); + f = sysfunc("duffzero"); + naddr(f, &p->to, 1); + afunclit(&p->to, f); + p->to.offset = 4*(128-cnt/widthptr); + } else { + p = appendpp(p, AADD, D_CONST, NREG, 4+frame+lo, D_REG, 1, 0); + p->reg = REGSP; + p = appendpp(p, AADD, D_CONST, NREG, cnt, D_REG, 2, 0); p->reg = 1; - p1 = p = appendp(p, AMOVW, D_REG, 0, 0, D_OREG, 1, 4); + p1 = p = appendpp(p, AMOVW, D_REG, 0, 0, D_OREG, 1, 4); p->scond |= C_PBIT; - p = appendp(p, ACMP, D_REG, 1, 0, D_NONE, 0, 0); + p = appendpp(p, ACMP, D_REG, 1, 0, D_NONE, 0, 0); p->reg = 2; - p = appendp(p, ABNE, D_NONE, NREG, 0, D_BRANCH, NREG, 0); + p = appendpp(p, ABNE, D_NONE, NREG, 0, D_BRANCH, NREG, 0); patch(p, p1); - } else { - first = 1; - j = (stkptrsize - stkzerosize)/widthptr * 2; - for(i=0; ias = as; - q->lineno = p->lineno; - q->from.type = ftype; - q->from.reg = freg; - q->from.offset = foffset; - q->to.type = ttype; - q->to.reg = treg; - q->to.offset = toffset; - q->link = p->link; - p->link = q; - return q; +static Prog* +appendpp(Prog *p, int as, int ftype, int freg, int32 foffset, int ttype, int treg, int32 toffset) +{ + Prog *q; + + q = mal(sizeof(*q)); + clearp(q); + q->as = as; + q->lineno = p->lineno; + q->from.type = ftype; + q->from.reg = freg; + q->from.offset = foffset; + q->to.type = ttype; + q->to.reg = treg; + q->to.offset = toffset; + q->link = p->link; + p->link = q; + return q; } // Sweep the prog list to mark any used nodes. @@ -88,13 +124,13 @@ void markautoused(Prog* p) { for (; p; p = p->link) { - if (p->as == ATYPE) + if (p->as == ATYPE || p->as == AVARDEF || p->as == AVARKILL) continue; - if (p->from.name == D_AUTO && p->from.node) + if (p->from.node) p->from.node->used = 1; - if (p->to.name == D_AUTO && p->to.node) + if (p->to.node) p->to.node->used = 1; } } @@ -110,6 +146,16 @@ fixautoused(Prog* p) *lp = p->link; continue; } + if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.node && !p->to.node->used) { + // Cannot remove VARDEF instruction, because - unlike TYPE handled above - + // VARDEFs are interspersed with other code, and a jump might be using the + // VARDEF as a target. Replace with a no-op instead. A later pass will remove + // the no-ops. + p->to.type = D_NONE; + p->to.node = N; + p->as = ANOP; + continue; + } if (p->from.name == D_AUTO && p->from.node) p->from.offset += p->from.node->stkdelta; @@ -245,7 +291,9 @@ ginscall(Node *f, int proc) nodconst(&con, types[TINT32], 0); p = gins(ACMP, &con, N); p->reg = 0; - patch(gbranch(ABNE, T, -1), retpc); + p = gbranch(ABEQ, T, +1); + cgen_ret(N); + patch(p, pc); } break; } @@ -459,16 +507,16 @@ cgen_ret(Node *n) { Prog *p; - genlist(n->list); // copy out args - if(hasdefer || curfn->exit) { - gjmp(retpc); - return; - } + if(n != N) + genlist(n->list); // copy out args + if(hasdefer) + ginscall(deferreturn, 0); + genlist(curfn->exit); p = gins(ARET, N, N); - if(n->op == ORETJMP) { + if(n != N && n->op == ORETJMP) { p->to.name = D_EXTERN; p->to.type = D_CONST; - p->to.sym = n->left->sym; + p->to.sym = linksym(n->left->sym); } } @@ -816,14 +864,13 @@ void clearfat(Node *nl) { uint32 w, c, q; - Node dst, nc, nz, end; + Node dst, nc, nz, end, r0, r1, *f; Prog *p, *pl; /* clear a fat object */ if(debug['g']) dump("\nclearfat", nl); - w = nl->type->width; // Avoid taking the address for simple enough types. if(componentgen(N, nl)) @@ -832,13 +879,17 @@ clearfat(Node *nl) c = w % 4; // bytes q = w / 4; // quads - regalloc(&dst, types[tptr], N); + r0.op = OREGISTER; + r0.val.u.reg = REGALLOC_R0; + r1.op = OREGISTER; + r1.val.u.reg = REGALLOC_R0 + 1; + regalloc(&dst, types[tptr], &r1); agen(nl, &dst); nodconst(&nc, types[TUINT32], 0); - regalloc(&nz, types[TUINT32], 0); + regalloc(&nz, types[TUINT32], &r0); cgen(&nc, &nz); - if(q >= 4) { + if(q > 128) { regalloc(&end, types[tptr], N); p = gins(AMOVW, &dst, &end); p->from.type = D_CONST; @@ -855,6 +906,12 @@ clearfat(Node *nl) patch(gbranch(ABNE, T, 0), pl); regfree(&end); + } else if(q >= 4) { + f = sysfunc("duffzero"); + p = gins(ADUFFZERO, N, f); + afunclit(&p->to, f); + // 4 and 128 = magic constants: see ../../pkg/runtime/asm_arm.s + p->to.offset = 4*(128-q); } else while(q > 0) { p = gins(AMOVW, &nz, &dst); @@ -901,7 +958,7 @@ expandchecks(Prog *firstp) p1->link = p->link; p->link = p1; p1->lineno = p->lineno; - p1->loc = 9999; + p1->pc = 9999; p1->as = AMOVW; p1->from.type = D_REG; p1->from.reg = reg; diff --git a/src/cmd/5g/gobj.c b/src/cmd/5g/gobj.c index 212ffc271..5e988878f 100644 --- a/src/cmd/5g/gobj.c +++ b/src/cmd/5g/gobj.c @@ -32,235 +32,6 @@ #include #include "gg.h" -void -zname(Biobuf *b, Sym *s, int t) -{ - BPUTC(b, ANAME); /* as */ - BPUTC(b, t); /* type */ - BPUTC(b, s->sym); /* sym */ - - Bputname(b, s); -} - -void -zfile(Biobuf *b, char *p, int n) -{ - BPUTC(b, ANAME); - BPUTC(b, D_FILE); - BPUTC(b, 1); - BPUTC(b, '<'); - Bwrite(b, p, n); - BPUTC(b, 0); -} - -void -zhist(Biobuf *b, int line, vlong offset) -{ - Addr a; - - BPUTC(b, AHISTORY); - BPUTC(b, C_SCOND_NONE); - BPUTC(b, NREG); - BPUTLE4(b, line); - zaddr(b, &zprog.from, 0, 0); - a = zprog.to; - if(offset != 0) { - a.offset = offset; - a.type = D_CONST; - } - zaddr(b, &a, 0, 0); -} - -void -zaddr(Biobuf *b, Addr *a, int s, int gotype) -{ - int32 l; - uint64 e; - int i; - char *n; - - switch(a->type) { - case D_STATIC: - case D_AUTO: - case D_EXTERN: - case D_PARAM: - // TODO(kaib): remove once everything seems to work - fatal("We should no longer generate these as types"); - - default: - BPUTC(b, a->type); - BPUTC(b, a->reg); - BPUTC(b, s); - BPUTC(b, a->name); - BPUTC(b, gotype); - } - - switch(a->type) { - default: - print("unknown type %d in zaddr\n", a->type); - - case D_NONE: - case D_REG: - case D_FREG: - case D_PSR: - break; - - case D_CONST2: - l = a->offset2; - BPUTLE4(b, l); // fall through - case D_OREG: - case D_CONST: - case D_SHIFT: - case D_STATIC: - case D_AUTO: - case D_EXTERN: - case D_PARAM: - l = a->offset; - BPUTLE4(b, l); - break; - - case D_BRANCH: - if(a->u.branch == nil) - fatal("unpatched branch"); - a->offset = a->u.branch->loc; - l = a->offset; - BPUTLE4(b, l); - break; - - case D_SCONST: - n = a->u.sval; - for(i=0; ioffset); - break; - - case D_FCONST: - ieeedtod(&e, a->u.dval); - BPUTLE4(b, e); - BPUTLE4(b, e >> 32); - break; - } -} - -static struct { - struct { Sym *sym; short type; } h[NSYM]; - int sym; -} z; - -static void -zsymreset(void) -{ - for(z.sym=0; z.symsym; - if(i < 0 || i >= NSYM) - i = 0; - if(z.h[i].type == t && z.h[i].sym == s) - return i; - i = z.sym; - s->sym = i; - zname(bout, s, t); - z.h[i].sym = s; - z.h[i].type = t; - if(++z.sym >= NSYM) - z.sym = 1; - *new = 1; - return i; -} - -static int -zsymaddr(Addr *a, int *new) -{ - int t; - - t = a->name; - if(t == D_ADDR) - t = a->name; - return zsym(a->sym, t, new); -} - -void -dumpfuncs(void) -{ - Plist *pl; - int sf, st, gf, gt, new; - Sym *s; - Prog *p; - - zsymreset(); - - // fix up pc - pcloc = 0; - for(pl=plist; pl!=nil; pl=pl->link) { - if(isblank(pl->name)) - continue; - for(p=pl->firstpc; p!=P; p=p->link) { - p->loc = pcloc; - if(p->as != ADATA && p->as != AGLOBL) - pcloc++; - } - } - - // put out functions - for(pl=plist; pl!=nil; pl=pl->link) { - if(isblank(pl->name)) - continue; - - // -S prints code; -SS prints code and data - if(debug['S'] && (pl->name || debug['S']>1)) { - s = S; - if(pl->name != N) - s = pl->name->sym; - print("\n--- prog list \"%S\" ---\n", s); - for(p=pl->firstpc; p!=P; p=p->link) - print("%P\n", p); - } - - for(p=pl->firstpc; p!=P; p=p->link) { - for(;;) { - sf = zsymaddr(&p->from, &new); - gf = zsym(p->from.gotype, D_EXTERN, &new); - if(new && sf == gf) - continue; - st = zsymaddr(&p->to, &new); - if(new && (st == sf || st == gf)) - continue; - gt = zsym(p->to.gotype, D_EXTERN, &new); - if(new && (gt == sf || gt == gf || gt == st)) - continue; - break; - } - - BPUTC(bout, p->as); - BPUTC(bout, p->scond); - BPUTC(bout, p->reg); - BPUTLE4(bout, p->lineno); - zaddr(bout, &p->from, sf, gf); - zaddr(bout, &p->to, st, gt); - } - } -} - int dsname(Sym *sym, int off, char *t, int n) { @@ -272,7 +43,7 @@ dsname(Sym *sym, int off, char *t, int n) p->from.etype = TINT32; p->from.offset = off; p->from.reg = NREG; - p->from.sym = sym; + p->from.sym = linksym(sym); p->reg = n; @@ -299,7 +70,7 @@ datastring(char *s, int len, Addr *a) a->etype = TINT32; a->offset = widthptr+4; // skip header a->reg = NREG; - a->sym = sym; + a->sym = linksym(sym); a->node = sym->def; } @@ -318,7 +89,7 @@ datagostring(Strlit *sval, Addr *a) a->etype = TINT32; a->offset = 0; // header a->reg = NREG; - a->sym = sym; + a->sym = linksym(sym); a->node = sym->def; } @@ -401,7 +172,7 @@ dstringptr(Sym *s, int off, char *str) p = gins(ADATA, N, N); p->from.type = D_OREG; p->from.name = D_EXTERN; - p->from.sym = s; + p->from.sym = linksym(s); p->from.offset = off; p->reg = widthptr; @@ -425,7 +196,7 @@ dgostrlitptr(Sym *s, int off, Strlit *lit) p = gins(ADATA, N, N); p->from.type = D_OREG; p->from.name = D_EXTERN; - p->from.sym = s; + p->from.sym = linksym(s); p->from.offset = off; p->reg = widthptr; datagostring(lit, &p->to); @@ -452,27 +223,6 @@ dgostringptr(Sym *s, int off, char *str) return dgostrlitptr(s, off, lit); } -int -duintxx(Sym *s, int off, uint64 v, int wid) -{ - Prog *p; - - off = rnd(off, wid); - - p = gins(ADATA, N, N); - p->from.type = D_OREG; - p->from.name = D_EXTERN; - p->from.sym = s; - p->from.offset = off; - p->reg = wid; - p->to.type = D_CONST; - p->to.name = D_NONE; - p->to.offset = v; - off += wid; - - return off; -} - int dsymptr(Sym *s, int off, Sym *x, int xoff) { @@ -483,12 +233,12 @@ dsymptr(Sym *s, int off, Sym *x, int xoff) p = gins(ADATA, N, N); p->from.type = D_OREG; p->from.name = D_EXTERN; - p->from.sym = s; + p->from.sym = linksym(s); p->from.offset = off; p->reg = widthptr; p->to.type = D_CONST; p->to.name = D_EXTERN; - p->to.sym = x; + p->to.sym = linksym(x); p->to.offset = xoff; off += widthptr; diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c index 27749b7a7..f66c87b5a 100644 --- a/src/cmd/5g/gsubr.c +++ b/src/cmd/5g/gsubr.c @@ -50,7 +50,7 @@ clearp(Prog *p) p->to.type = D_NONE; p->to.name = D_NONE; p->to.reg = NREG; - p->loc = pcloc; + p->pc = pcloc; pcloc++; } @@ -138,7 +138,7 @@ patch(Prog *p, Prog *to) if(p->to.type != D_BRANCH) fatal("patch: not a branch"); p->to.u.branch = to; - p->to.offset = to->loc; + p->to.offset = to->pc; } Prog* @@ -162,12 +162,7 @@ newplist(void) { Plist *pl; - pl = mal(sizeof(*pl)); - if(plist == nil) - plist = pl; - else - plast->link = pl; - plast = pl; + pl = linknewplist(ctxt); pc = mal(sizeof(*pc)); clearp(pc); @@ -200,8 +195,8 @@ ggloblnod(Node *nam) p = gins(AGLOBL, nam, N); p->lineno = nam->lineno; - p->from.gotype = ngotype(nam); - p->to.sym = S; + p->from.sym->gotype = linksym(ngotype(nam)); + p->to.sym = nil; p->to.type = D_CONST; p->to.offset = nam->type->width; if(nam->readonly) @@ -228,7 +223,7 @@ ggloblsym(Sym *s, int32 width, int dupok, int rodata) p = gins(AGLOBL, N, N); p->from.type = D_OREG; p->from.name = D_EXTERN; - p->from.sym = s; + p->from.sym = linksym(s); p->to.type = D_CONST; p->to.name = D_NONE; p->to.offset = width; @@ -246,7 +241,7 @@ gtrack(Sym *s) p = gins(AUSEFIELD, N, N); p->from.type = D_OREG; p->from.name = D_EXTERN; - p->from.sym = s; + p->from.sym = linksym(s); } int @@ -275,7 +270,7 @@ afunclit(Addr *a, Node *n) if(a->type == D_CONST && a->name == D_EXTERN || a->type == D_REG) { a->type = D_OREG; if(n->op == ONAME) - a->sym = n->sym; + a->sym = linksym(n->sym); } } @@ -475,6 +470,7 @@ Node* nodarg(Type *t, int fp) { Node *n; + NodeList *l; Type *first; Iter savet; @@ -496,6 +492,14 @@ nodarg(Type *t, int fp) if(t->etype != TFIELD) fatal("nodarg: not field %T", t); + if(fp == 1) { + for(l=curfn->dcl; l; l=l->next) { + n = l->n; + if((n->class == PPARAM || n->class == PPARAMOUT) && !isblanksym(t->sym) && n->sym == t->sym) + return n; + } + } + n = nod(ONAME, N, N); n->type = t->type; n->sym = t->sym; @@ -1196,10 +1200,12 @@ gregshift(int as, Node *lhs, int32 stype, Node *reg, Node *rhs) void naddr(Node *n, Addr *a, int canemitcode) { + Sym *s; + a->type = D_NONE; a->name = D_NONE; a->reg = NREG; - a->gotype = S; + a->gotype = nil; a->node = N; a->etype = 0; if(n == N) @@ -1223,7 +1229,7 @@ naddr(Node *n, Addr *a, int canemitcode) a->type = D_FREG; a->reg = n->val.u.reg - REGALLOC_F0; } - a->sym = S; + a->sym = nil; break; case OINDEX: @@ -1250,7 +1256,7 @@ naddr(Node *n, Addr *a, int canemitcode) case OINDREG: a->type = D_OREG; a->reg = n->val.u.reg; - a->sym = n->sym; + a->sym = linksym(n->sym); a->offset = n->xoffset; break; @@ -1260,22 +1266,24 @@ naddr(Node *n, Addr *a, int canemitcode) a->etype = simtype[n->left->type->etype]; a->width = n->left->type->width; a->offset = n->xoffset; - a->sym = n->left->sym; + a->sym = linksym(n->left->sym); a->type = D_OREG; a->name = D_PARAM; a->node = n->left->orig; break; case OCLOSUREVAR: + if(!curfn->needctxt) + fatal("closurevar without needctxt"); a->type = D_OREG; a->reg = 7; a->offset = n->xoffset; - a->sym = S; + a->sym = nil; break; case OCFUNC: naddr(n->left, a, canemitcode); - a->sym = n->left->sym; + a->sym = linksym(n->left->sym); break; case ONAME: @@ -1287,17 +1295,17 @@ naddr(Node *n, Addr *a, int canemitcode) a->width = n->type->width; } a->offset = n->xoffset; - a->sym = n->sym; + s = n->sym; a->node = n->orig; //if(a->node >= (Node*)&n) // fatal("stack node"); - if(a->sym == S) - a->sym = lookup(".noname"); + if(s == S) + s = lookup(".noname"); if(n->method) { if(n->type != T) if(n->type->sym != S) if(n->type->sym->pkg != nil) - a->sym = pkglookup(a->sym->name, n->type->sym->pkg); + s = pkglookup(s->name, n->type->sym->pkg); } a->type = D_OREG; @@ -1317,9 +1325,10 @@ naddr(Node *n, Addr *a, int canemitcode) case PFUNC: a->name = D_EXTERN; a->type = D_CONST; - a->sym = funcsym(a->sym); + s = funcsym(s); break; } + a->sym = linksym(s); break; case OLITERAL: @@ -1333,7 +1342,7 @@ naddr(Node *n, Addr *a, int canemitcode) break; case CTINT: case CTRUNE: - a->sym = S; + a->sym = nil; a->type = D_CONST; a->offset = mpgetfix(n->val.u.xval); break; @@ -1341,12 +1350,12 @@ naddr(Node *n, Addr *a, int canemitcode) datagostring(n->val.u.sval, a); break; case CTBOOL: - a->sym = S; + a->sym = nil; a->type = D_CONST; a->offset = n->val.u.bval; break; case CTNIL: - a->sym = S; + a->sym = nil; a->type = D_CONST; a->offset = 0; break; @@ -1366,7 +1375,7 @@ naddr(Node *n, Addr *a, int canemitcode) naddr(n->left, a, canemitcode); if(a->type == D_CONST && a->offset == 0) break; // ptr(nil) - a->etype = simtype[TUINTPTR]; + a->etype = simtype[tptr]; a->offset += Array_array; a->width = widthptr; break; @@ -1592,6 +1601,7 @@ optoas(int op, Type *t) case CASE(OADD, TINT32): case CASE(OADD, TUINT32): case CASE(OADD, TPTR32): + case CASE(OADDPTR, TPTR32): a = AADD; break; diff --git a/src/cmd/5g/list.c b/src/cmd/5g/list.c deleted file mode 100644 index 6c3f1d744..000000000 --- a/src/cmd/5g/list.c +++ /dev/null @@ -1,342 +0,0 @@ -// Derived from Inferno utils/5c/list.c -// http://code.google.com/p/inferno-os/source/browse/utils/5c/list.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 -#include -#include "gg.h" - -// TODO(kaib): make 5g/list.c congruent with 5l/list.c - -static int sconsize; -void -listinit(void) -{ - - fmtinstall('A', Aconv); // as - fmtinstall('C', Cconv); // conditional execution bit - fmtinstall('P', Pconv); // Prog* - fmtinstall('D', Dconv); // Addr* - fmtinstall('Y', Yconv); // sconst - fmtinstall('R', Rconv); // register - fmtinstall('M', Mconv); // names -} - -int -Pconv(Fmt *fp) -{ - 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 && p->as != AGLOBL) - snprint(str, sizeof(str), "%.4d (%L) %-7s %D,%D", - p->loc, p->lineno, str1, &p->from, &p->to); - else - 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: - snprint(str, sizeof(str), "%.4d (%L) %-7A %D/%d,%D", - p->loc, p->lineno, p->as, &p->from, p->reg, &p->to); - break; - } - return fmtstrcpy(fp, str); -} - -int -Dconv(Fmt *fp) -{ - char str[STRINGSZ]; - const char *op; - Addr *a; - int i; - int32 v; - - a = va_arg(fp->args, Addr*); - if(a == A) { - sprint(str, ""); - goto conv; - } - i = a->type; - switch(i) { - - default: - sprint(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, "%M(R%d)(NONE)", a, a->reg); - break; - - case D_CONST: - if(a->reg != NREG) - sprint(str, "$%M(R%d)", a, a->reg); - else - sprint(str, "$%M", a); - break; - - case D_CONST2: - sprint(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); - else - sprint(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); - break; - - case D_OCONST: - sprint(str, "$*$%M", a); - if(a->reg != NREG) - sprint(str, "%M(R%d)(CONST)", a, a->reg); - break; - - case D_OREG: - if(a->reg != NREG) - sprint(str, "%M(R%d)", a, a->reg); - else - sprint(str, "%M", a); - break; - - case D_REG: - sprint(str, "R%d", a->reg); - if(a->name != D_NONE || a->sym != S) - sprint(str, "%M(R%d)(REG)", a, a->reg); - break; - - case D_REGREG: - sprint(str, "(R%d,R%d)", a->reg, (int)a->offset); - if(a->name != D_NONE || a->sym != S) - sprint(str, "%M(R%d)(REG)", a, a->reg); - break; - - case D_REGREG2: - sprint(str, "R%d,R%d", a->reg, (int)a->offset); - if(a->name != D_NONE || a->sym != S) - sprint(str, "%M(R%d)(REG)", a, a->reg); - break; - - case D_FREG: - sprint(str, "F%d", a->reg); - if(a->name != D_NONE || a->sym != S) - sprint(str, "%M(R%d)(REG)", a, a->reg); - break; - - case D_BRANCH: - if(a->u.branch == P || a->u.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->u.branch->loc); - else - sprint(str, "%d(APC)", a->u.branch->loc); - break; - - case D_FCONST: - snprint(str, sizeof(str), "$(%.17e)", a->u.dval); - break; - - case D_SCONST: - snprint(str, sizeof(str), "$\"%Y\"", a->u.sval); - break; - - // TODO(kaib): Add back -// case D_ADDR: -// a->type = a->index; -// a->index = D_NONE; -// snprint(str, sizeof(str), "$%D", a); -// a->index = a->type; -// a->type = D_ADDR; -// goto conv; - } -conv: - fmtstrcpy(fp, str); - if(a->gotype) - fmtprint(fp, "{%s}", a->gotype->name); - return 0; -} - -int -Aconv(Fmt *fp) -{ - int i; - - i = va_arg(fp->args, int); - return fmtstrcpy(fp, anames[i]); -} - -char* strcond[16] = -{ - ".EQ", - ".NE", - ".HS", - ".LO", - ".MI", - ".PL", - ".VS", - ".VC", - ".HI", - ".LS", - ".GE", - ".LT", - ".GT", - ".LE", - "", - ".NV" -}; - -int -Cconv(Fmt *fp) -{ - char s[STRINGSZ]; - int c; - - c = va_arg(fp->args, int); - strcpy(s, strcond[c & C_SCOND]); - if(c & C_SBIT) - strcat(s, ".S"); - if(c & C_PBIT) - strcat(s, ".P"); - if(c & C_WBIT) - strcat(s, ".W"); - if(c & C_UBIT) /* ambiguous with FBIT */ - strcat(s, ".U"); - return fmtstrcpy(fp, s); -} - -int -Yconv(Fmt *fp) -{ - int i, c; - char str[STRINGSZ], *p, *a; - - a = va_arg(fp->args, char*); - p = str; - for(i=0; i= 'a' && c <= 'z') || - (c >= 'A' && c <= 'Z') || - (c >= '0' && c <= '9')) { - *p++ = c; - continue; - } - *p++ = '\\'; - switch(c) { - default: - if(c < 040 || c >= 0177) - break; /* not portable */ - p[-1] = c; - continue; - case 0: - *p++ = 'z'; - continue; - case '\\': - case '"': - *p++ = c; - continue; - case '\n': - *p++ = 'n'; - continue; - case '\t': - *p++ = 't'; - continue; - } - *p++ = (c>>6) + '0'; - *p++ = ((c>>3) & 7) + '0'; - *p++ = (c & 7) + '0'; - } - *p = 0; - return fmtstrcpy(fp, str); -} - -int -Rconv(Fmt *fp) -{ - int r; - char str[STRINGSZ]; - - r = va_arg(fp->args, int); - snprint(str, sizeof(str), "R%d", r); - return fmtstrcpy(fp, str); -} - -int -Mconv(Fmt *fp) -{ - char str[STRINGSZ]; - Addr *a; - - a = va_arg(fp->args, Addr*); - switch(a->name) { - default: - snprint(str, sizeof(str), "GOK-name(%d)", a->name); - break; - - case D_NONE: - snprint(str, sizeof(str), "%d", a->offset); - break; - - case D_EXTERN: - snprint(str, sizeof(str), "%S+%d(SB)", a->sym, a->offset); - break; - - case D_STATIC: - snprint(str, sizeof(str), "%S<>+%d(SB)", a->sym, a->offset); - break; - - case D_AUTO: - snprint(str, sizeof(str), "%S+%d(SP)", a->sym, a->offset); - break; - - case D_PARAM: - snprint(str, sizeof(str), "%S+%d(FP)", a->sym, a->offset); - break; - } - return fmtstrcpy(fp, str); -} diff --git a/src/cmd/5g/opt.h b/src/cmd/5g/opt.h index 15b9d1458..e3e3f78ed 100644 --- a/src/cmd/5g/opt.h +++ b/src/cmd/5g/opt.h @@ -96,6 +96,7 @@ EXTERN Bits externs; EXTERN Bits params; EXTERN Bits consts; EXTERN Bits addrs; +EXTERN Bits ivar; EXTERN Bits ovar; EXTERN int change; EXTERN int32 maxnr; diff --git a/src/cmd/5g/peep.c b/src/cmd/5g/peep.c index c78fb3d1c..4aa645206 100644 --- a/src/cmd/5g/peep.c +++ b/src/cmd/5g/peep.c @@ -287,6 +287,8 @@ subprop(Flow *r0) if(uniqs(r) == nil) break; p = r->prog; + if(p->as == AVARDEF || p->as == AVARKILL) + continue; proginfo(&info, p); if(info.flags & Call) return 0; @@ -397,7 +399,7 @@ copy1(Adr *v1, Adr *v2, Flow *r, int f) if(debug['P']) print("; merge; f=%d", f); } - t = copyu(p, v2, A); + t = copyu(p, v2, nil); switch(t) { case 2: /* rar, can't split */ if(debug['P']) @@ -435,7 +437,7 @@ copy1(Adr *v1, Adr *v2, Flow *r, int f) break; } if(!f) { - t = copyu(p, v1, A); + t = copyu(p, v1, nil); if(!f && (t == 2 || t == 3 || t == 4)) { f = 1; if(debug['P']) @@ -479,7 +481,7 @@ constprop(Adr *c1, Adr *v1, Flow *r) if(debug['P']) print("; sub%D/%D", &p->from, v1); p->from = *v1; - } else if(copyu(p, v1, A) > 1) { + } else if(copyu(p, v1, nil) > 1) { if(debug['P']) print("; %Dset; return\n", v1); return; @@ -592,10 +594,10 @@ shiftprop(Flow *r) p1 = r1->prog; if(debug['P']) print("\n%P", p1); - switch(copyu(p1, &p->to, A)) { + switch(copyu(p1, &p->to, nil)) { 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)) + if((p->from.type == D_REG && copyu(p1, &p->from, nil) > 1) || + (a.type == D_REG && copyu(p1, &a, nil) > 1)) FAIL("args modified"); continue; case 3: /* set, not used */ @@ -663,7 +665,7 @@ shiftprop(Flow *r) p1 = r1->prog; if(debug['P']) print("\n%P", p1); - switch(copyu(p1, &p->to, A)) { + switch(copyu(p1, &p->to, nil)) { case 0: /* not used or set */ continue; case 3: /* set, not used */ @@ -719,7 +721,7 @@ findpre(Flow *r, Adr *v) for(r1=uniqp(r); r1!=nil; r=r1,r1=uniqp(r)) { if(uniqs(r1) != r) return nil; - switch(copyu(r1->prog, v, A)) { + switch(copyu(r1->prog, v, nil)) { case 1: /* used */ case 2: /* read-alter-rewrite */ return nil; @@ -745,7 +747,7 @@ findinc(Flow *r, Flow *r2, Adr *v) for(r1=uniqs(r); r1!=nil && r1!=r2; r=r1,r1=uniqs(r)) { if(uniqp(r1) != r) return nil; - switch(copyu(r1->prog, v, A)) { + switch(copyu(r1->prog, v, nil)) { case 0: /* not touched */ continue; case 4: /* set and used */ @@ -787,7 +789,7 @@ nochange(Flow *r, Flow *r2, Prog *p) for(; r!=nil && r!=r2; r=uniqs(r)) { p = r->prog; for(i=0; i 1) + if(copyu(p, &a[i], nil) > 1) return 0; } return 1; @@ -800,7 +802,7 @@ findu1(Flow *r, Adr *v) if(r->active) return 0; r->active = 1; - switch(copyu(r->prog, v, A)) { + switch(copyu(r->prog, v, nil)) { case 1: /* used */ case 2: /* read-alter-rewrite */ case 4: /* set and used */ @@ -943,7 +945,7 @@ copyu(Prog *p, Adr *v, Adr *s) if(v->type != D_REG) return 0; if(p->from.type == D_CONST) { /* read reglist, read/rar */ - if(s != A) { + if(s != nil) { if(p->from.offset&(1<reg)) return 1; if(copysub(&p->to, v, s, 1)) @@ -958,7 +960,7 @@ copyu(Prog *p, Adr *v, Adr *s) if(p->from.offset&(1<reg)) return 1; } else { /* read/rar, write reglist */ - if(s != A) { + if(s != nil) { if(p->to.offset&(1<reg)) return 1; if(copysub(&p->from, v, s, 1)) @@ -1003,7 +1005,7 @@ copyu(Prog *p, Adr *v, Adr *s) return 2; } } - if(s != A) { + if(s != nil) { if(copysub(&p->from, v, s, 1)) return 1; if(!copyas(&p->to, v)) @@ -1063,7 +1065,7 @@ copyu(Prog *p, Adr *v, Adr *s) case ACMN: case ACASE: case ATST: /* read,, */ - if(s != A) { + if(s != nil) { if(copysub(&p->from, v, s, 1)) return 1; if(copysub1(p, v, s, 1)) @@ -1108,7 +1110,7 @@ copyu(Prog *p, Adr *v, Adr *s) case ABLT: case ABGT: case ABLE: - if(s != A) { + if(s != nil) { if(copysub(&p->from, v, s, 1)) return 1; return copysub1(p, v, s, 1); @@ -1120,7 +1122,7 @@ copyu(Prog *p, Adr *v, Adr *s) return 0; case AB: /* funny */ - if(s != A) { + if(s != nil) { if(copysub(&p->to, v, s, 1)) return 1; return 0; @@ -1130,7 +1132,7 @@ copyu(Prog *p, Adr *v, Adr *s) return 0; case ARET: /* funny */ - if(s != A) + if(s != nil) return 1; return 3; @@ -1138,7 +1140,7 @@ copyu(Prog *p, Adr *v, Adr *s) if(v->type == D_REG) { if(v->reg <= REGEXT && v->reg > exregoffset) return 2; - if(v->reg == (uchar)REGARG) + if(v->reg == REGARG) return 2; } if(v->type == D_FREG) @@ -1147,7 +1149,7 @@ copyu(Prog *p, Adr *v, Adr *s) if(p->from.type == D_REG && v->type == D_REG && p->from.reg == v->reg) return 2; - if(s != A) { + if(s != nil) { if(copysub(&p->to, v, s, 1)) return 1; return 0; @@ -1155,15 +1157,37 @@ copyu(Prog *p, Adr *v, Adr *s) if(copyau(&p->to, v)) return 4; return 3; - + case ADUFFZERO: + // R0 is zero, used by DUFFZERO, cannot be substituted. + // R1 is ptr to memory, used and set, cannot be substituted. + if(v->type == D_REG) { + if(v->reg == REGALLOC_R0) + return 1; + if(v->reg == REGALLOC_R0+1) + return 2; + } + return 0; + case ADUFFCOPY: + // R0 is scratch, set by DUFFCOPY, cannot be substituted. + // R1, R2 areptr to src, dst, used and set, cannot be substituted. + if(v->type == D_REG) { + if(v->reg == REGALLOC_R0) + return 3; + if(v->reg == REGALLOC_R0+1 || v->reg == REGALLOC_R0+2) + return 2; + } + return 0; + case ATEXT: /* funny */ if(v->type == D_REG) - if(v->reg == (uchar)REGARG) + if(v->reg == REGARG) return 3; return 0; case APCDATA: case AFUNCDATA: + case AVARDEF: + case AVARKILL: return 0; } } @@ -1241,35 +1265,79 @@ copyau(Adr *a, Adr *v) return 0; } +static int +a2type(Prog *p) +{ + if(p->reg == NREG) + return D_NONE; + + switch(p->as) { + default: + fatal("a2type: unhandled %P", p); + + case AAND: + case AEOR: + case ASUB: + case ARSB: + case AADD: + case AADC: + case ASBC: + case ARSC: + case ATST: + case ATEQ: + case ACMP: + case ACMN: + case AORR: + case ABIC: + case AMVN: + case ASRL: + case ASRA: + case ASLL: + case AMULU: + case ADIVU: + case AMUL: + case ADIV: + case AMOD: + case AMODU: + case AMULA: + case AMULL: + case AMULAL: + case AMULLU: + case AMULALU: + case AMULWT: + case AMULWB: + case AMULAWT: + case AMULAWB: + return D_REG; + + case ACMPF: + case ACMPD: + case AADDF: + case AADDD: + case ASUBF: + case ASUBD: + case AMULF: + case AMULD: + case ADIVF: + case ADIVD: + case ASQRTF: + case ASQRTD: + case AABSF: + case AABSD: + return D_FREG; + } +} + /* * compare v to the center * register in p (p->reg) - * the trick is that this - * register might be D_REG - * D_FREG. there are basically - * two cases, - * ADD r,r,r - * CMP r,r, */ static int copyau1(Prog *p, Adr *v) { - - if(regtyp(v)) - if(p->reg == v->reg) { - if(p->to.type != D_NONE) { - if(v->type == p->to.type) - return 1; - return 0; - } - if(p->from.type != D_NONE) { - if(v->type == p->from.type) - return 1; - return 0; - } - print("copyau1: can't tell %P\n", p); - } - return 0; + if(v->type == D_REG && v->reg == NREG) + return 0; + return p->reg == v->reg && a2type(p) == v->type; } /* diff --git a/src/cmd/5g/prog.c b/src/cmd/5g/prog.c index 5aa6163d8..797bc0718 100644 --- a/src/cmd/5g/prog.c +++ b/src/cmd/5g/prog.c @@ -26,9 +26,11 @@ static ProgInfo progtable[ALAST] = { [ATEXT]= {Pseudo}, [AFUNCDATA]= {Pseudo}, [APCDATA]= {Pseudo}, - [AUNDEF]= {OK}, + [AUNDEF]= {Break}, [AUSEFIELD]= {OK}, [ACHECKNIL]= {LeftRead}, + [AVARDEF]= {Pseudo | RightWrite}, + [AVARKILL]= {Pseudo | RightWrite}, // NOP is an internal no-op that also stands // for USED and SET annotations, not the Intel opcode. @@ -91,6 +93,12 @@ static ProgInfo progtable[ALAST] = { [AMOVF]= {SizeF | LeftRead | RightWrite | Move}, [AMOVH]= {SizeW | LeftRead | RightWrite | Move}, [AMOVW]= {SizeL | LeftRead | RightWrite | Move}, + // In addtion, duffzero reads R0,R1 and writes R1. This fact is + // encoded in peep.c + [ADUFFZERO]= {Call}, + // In addtion, duffcopy reads R1,R2 and writes R0,R1,R2. This fact is + // encoded in peep.c + [ADUFFCOPY]= {Call}, // These should be split into the two different conversions instead // of overloading the one. diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c index d2a8cc488..4762df506 100644 --- a/src/cmd/5g/reg.c +++ b/src/cmd/5g/reg.c @@ -56,30 +56,6 @@ rcmp(const void *a1, const void *a2) 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); - for(z=0; zopt = nil; return; + } + firstr = (Reg*)g->start; for(r = firstr; r != R; r = (Reg*)r->f.link) { p = r->f.prog; + if(p->as == AVARDEF || p->as == AVARKILL) + continue; proginfo(&info, p); // Avoid making variables for direct-called functions. @@ -270,6 +251,26 @@ regopt(Prog *firstp) if(debug['R'] && debug['v']) dumpit("pass2", &firstr->f, 1); + /* + * pass 2.5 + * iterate propagating fat vardef covering forward + * r->act records vars with a VARDEF since the last CALL. + * (r->act will be reused in pass 5 for something else, + * but we'll be done with it by then.) + */ + active = 0; + for(r = firstr; r != R; r = (Reg*)r->f.link) { + r->f.active = 0; + r->act = zbits; + } + for(r = firstr; r != R; r = (Reg*)r->f.link) { + p = r->f.prog; + if(p->as == AVARDEF && isfat(p->to.node->type) && p->to.node->opt != nil) { + active++; + walkvardef(p->to.node, r, active); + } + } + /* * pass 3 * iterate propagating usage @@ -470,6 +471,14 @@ brk: if(debug['R'] && debug['v']) dumpit("pass6", &firstr->f, 1); + /* + * free aux structures. peep allocates new ones. + */ + for(i=0; iopt = nil; + flowend(g); + firstr = R; + /* * pass 7 * peep-hole on basic block @@ -523,20 +532,44 @@ brk: } if(p->as == AMOVW && vreg != 0) { - if(p->from.sym != S) + if(p->from.sym != nil) if(p->from.name == D_AUTO || p->from.name == D_PARAM) { p->from.offset += vreg; // print("%P adjusting from %d %d\n", p, vreg, p->from.type); } - if(p->to.sym != S) + if(p->to.sym != nil) if(p->to.name == D_AUTO || p->to.name == D_PARAM) { p->to.offset += vreg; // print("%P adjusting to %d %d\n", p, vreg, p->from.type); } } } +} - flowend(g); +static void +walkvardef(Node *n, Reg *r, int active) +{ + Reg *r1, *r2; + int bn; + Var *v; + + for(r1=r; r1!=R; r1=(Reg*)r1->f.s1) { + if(r1->f.active == active) + break; + r1->f.active = active; + if(r1->f.prog->as == AVARKILL && r1->f.prog->to.node == n) + break; + for(v=n->opt; v!=nil; v=v->nextinnode) { + bn = v - var; + r1->act.b[bn/32] |= 1L << (bn%32); + } + if(r1->f.prog->as == ABL) + break; + } + + for(r2=r; r2!=r1; r2=(Reg*)r2->f.s1) + if(r2->f.s2 != nil) + walkvardef(n, (Reg*)r2->f.s2, active); } void @@ -551,6 +584,10 @@ addsplits(void) continue; if(r->f.prog->as == ABL) continue; + if(r->f.prog->as == ADUFFZERO) + continue; + if(r->f.prog->as == ADUFFCOPY) + continue; for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link) { if(r1->f.loop <= 1) continue; @@ -596,11 +633,11 @@ addmove(Reg *r, int bn, int rn, int f) a = &p1->to; a->name = v->name; a->node = v->node; - a->sym = v->node->sym; + a->sym = linksym(v->node->sym); a->offset = v->offset; a->etype = v->etype; a->type = D_OREG; - if(a->etype == TARRAY || a->sym == S) + if(a->etype == TARRAY || a->sym == nil) a->type = D_CONST; if(v->addr) @@ -790,6 +827,16 @@ mkvar(Reg *r, Adr *a) if(nvar >= NVAR) { if(debug['w'] > 1 && node) fatal("variable not optimized: %D", a); + + // If we're not tracking a word in a variable, mark the rest as + // having its address taken, so that we keep the whole thing + // live at all calls. otherwise we might optimize away part of + // a variable but not all of it. + for(i=0; inode == node) + v->addr = 1; + } goto none; } @@ -804,9 +851,13 @@ mkvar(Reg *r, Adr *a) v->addr = flag; // funny punning v->node = node; - if(debug['R']) - print("bit=%2d et=%2E w=%d+%d %#N %D flag=%d\n", i, et, o, w, node, a, v->addr); - + // node->opt is the head of a linked list + // of Vars within the given Node, so that + // we can start at a Var and find all the other + // Vars in the same Go variable. + v->nextinnode = node->opt; + node->opt = v; + bit = blsh(i); if(n == D_EXTERN || n == D_STATIC) for(z=0; zclass == PPARAM) + for(z=0; zclass == PPARAMOUT) + for(z=0; zaddrtaken) + v->addr = 1; + + // Disable registerization for globals, because: + // (1) we might panic at any time and we want the recovery code + // to see the latest values (issue 1304). + // (2) we don't know what pointers might point at them and we want + // loads via those pointers to see updated values and vice versa (issue 7995). + // + // Disable registerization for results if using defer, because the deferred func + // might recover and return, causing the current values to be used. + if(node->class == PEXTERN || (hasdefer && node->class == PPARAMOUT)) + v->addr = 1; + + if(debug['R']) + print("bit=%2d et=%2E w=%d+%d %#N %D flag=%d\n", i, et, o, w, node, a, v->addr); + return bit; none: @@ -825,7 +915,8 @@ void prop(Reg *r, Bits ref, Bits cal) { Reg *r1, *r2; - int z; + int z, i, j; + Var *v, *v1; for(r1 = r; r1 != R; r1 = (Reg*)r1->f.p1) { for(z=0; zf.prog)) break; + + // Mark all input variables (ivar) as used, because that's what the + // liveness bitmaps say. The liveness bitmaps say that so that a + // panic will not show stale values in the parameter dump. + // Mark variables with a recent VARDEF (r1->act) as used, + // so that the optimizer flushes initializations to memory, + // so that if a garbage collection happens during this CALL, + // the collector will see initialized memory. Again this is to + // match what the liveness bitmaps say. for(z=0; zact.b[z]; ref.b[z] = 0; } + + // cal.b is the current approximation of what's live across the call. + // Every bit in cal.b is a single stack word. For each such word, + // find all the other tracked stack words in the same Go variable + // (struct/slice/string/interface) and mark them live too. + // This is necessary because the liveness analysis for the garbage + // collector works at variable granularity, not at word granularity. + // It is fundamental for slice/string/interface: the garbage collector + // needs the whole value, not just some of the words, in order to + // interpret the other bits correctly. Specifically, slice needs a consistent + // ptr and cap, string needs a consistent ptr and len, and interface + // needs a consistent type word and data word. + for(z=0; z= nvar || ((cal.b[z]>>i)&1) == 0) + continue; + v = var+z*32+i; + if(v->node->opt == nil) // v represents fixed register, not Go variable + continue; + + // v->node->opt is the head of a linked list of Vars + // corresponding to tracked words from the Go variable v->node. + // Walk the list and set all the bits. + // For a large struct this could end up being quadratic: + // after the first setting, the outer loop (for z, i) would see a 1 bit + // for all of the remaining words in the struct, and for each such + // word would go through and turn on all the bits again. + // To avoid the quadratic behavior, we only turn on the bits if + // v is the head of the list or if the head's bit is not yet turned on. + // This will set the bits at most twice, keeping the overall loop linear. + v1 = v->node->opt; + j = v1 - var; + if(v == v1 || ((cal.b[j/32]>>(j&31))&1) == 0) { + for(; v1 != nil; v1 = v1->nextinnode) { + j = v1 - var; + cal.b[j/32] |= 1<<(j&31); + } + } + } + } break; case ATEXT: @@ -863,17 +1005,6 @@ prop(Reg *r, Bits ref, Bits cal) ref.b[z] = 0; } break; - - default: - // Work around for issue 1304: - // flush modified globals before each instruction. - for(z=0; zset.b[z]) | @@ -1004,18 +1135,20 @@ paint1(Reg *r, int bn) r->act.b[z] |= bb; p = r->f.prog; - if(r->use1.b[z] & bb) { - change += CREF * r->f.loop; - if(debug['R'] > 1) - print("%d%P\tu1 %Q $%d\n", r->f.loop, - p, blsh(bn), change); - } - if((r->use2.b[z]|r->set.b[z]) & bb) { - change += CREF * r->f.loop; - if(debug['R'] > 1) - print("%d%P\tu2 %Q $%d\n", r->f.loop, - p, blsh(bn), change); + if(r->f.prog->as != ANOP) { // don't give credit for NOPs + if(r->use1.b[z] & bb) { + change += CREF * r->f.loop; + if(debug['R'] > 1) + print("%d%P\tu1 %Q $%d\n", r->f.loop, + p, blsh(bn), change); + } + if((r->use2.b[z]|r->set.b[z]) & bb) { + change += CREF * r->f.loop; + if(debug['R'] > 1) + print("%d%P\tu2 %Q $%d\n", r->f.loop, + p, blsh(bn), change); + } } if(STORE(r) & r->regdiff.b[z] & bb) { @@ -1172,7 +1305,7 @@ paint3(Reg *r, int bn, int32 rb, int rn) void addreg(Adr *a, int rn) { - a->sym = 0; + a->sym = nil; a->name = D_NONE; a->type = D_REG; a->reg = rn; @@ -1292,9 +1425,9 @@ dumpit(char *str, Flow *r0, int isreg) if(r1 != nil) { print(" pred:"); for(; r1 != nil; r1 = r1->p2link) - print(" %.4ud", r1->prog->loc); + print(" %.4ud", (int)r1->prog->pc); if(r->p1 != nil) - print(" (and %.4ud)", r->p1->prog->loc); + print(" (and %.4ud)", (int)r->p1->prog->pc); else print(" (only)"); print("\n"); @@ -1303,7 +1436,7 @@ dumpit(char *str, Flow *r0, int isreg) // if(r1 != nil) { // print(" succ:"); // for(; r1 != R; r1 = r1->s1) -// print(" %.4ud", r1->prog->loc); +// print(" %.4ud", (int)r1->prog->pc); // print("\n"); // } } diff --git a/src/cmd/5l/5.out.h b/src/cmd/5l/5.out.h index e8cf83ddd..9e8aceecb 100644 --- a/src/cmd/5l/5.out.h +++ b/src/cmd/5l/5.out.h @@ -198,6 +198,12 @@ enum as AFUNCDATA, APCDATA, ACHECKNIL, + AVARDEF, + AVARKILL, + ADUFFCOPY, + ADUFFZERO, + + AMRC, // MRC/MCR ALAST, }; @@ -233,62 +239,43 @@ enum as #define SHIFT_AR 2<<5 #define SHIFT_RR 3<<5 +enum +{ /* type/name */ -#define D_GOK 0 -#define D_NONE 1 + D_GOK = 0, + D_NONE = 1, /* type */ -#define D_BRANCH (D_NONE+1) -#define D_OREG (D_NONE+2) -#define D_CONST (D_NONE+7) -#define D_FCONST (D_NONE+8) -#define D_SCONST (D_NONE+9) -#define D_PSR (D_NONE+10) -#define D_REG (D_NONE+12) -#define D_FREG (D_NONE+13) -#define D_FILE (D_NONE+16) -#define D_OCONST (D_NONE+17) -#define D_FILE1 (D_NONE+18) - -#define D_SHIFT (D_NONE+19) -#define D_FPCR (D_NONE+20) -#define D_REGREG (D_NONE+21) // (reg, reg) -#define D_ADDR (D_NONE+22) - -#define D_SBIG (D_NONE+23) -#define D_CONST2 (D_NONE+24) - -#define D_REGREG2 (D_NONE+25) // reg, reg + D_BRANCH = (D_NONE+1), + D_OREG = (D_NONE+2), + D_CONST = (D_NONE+7), + D_FCONST = (D_NONE+8), + D_SCONST = (D_NONE+9), + D_PSR = (D_NONE+10), + D_REG = (D_NONE+12), + D_FREG = (D_NONE+13), + D_FILE = (D_NONE+16), + D_OCONST = (D_NONE+17), + D_FILE1 = (D_NONE+18), + + D_SHIFT = (D_NONE+19), + D_FPCR = (D_NONE+20), + D_REGREG = (D_NONE+21), // (reg, reg) + D_ADDR = (D_NONE+22), + + D_SBIG = (D_NONE+23), + D_CONST2 = (D_NONE+24), + + D_REGREG2 = (D_NONE+25), // reg, reg /* name */ -#define D_EXTERN (D_NONE+3) -#define D_STATIC (D_NONE+4) -#define D_AUTO (D_NONE+5) -#define D_PARAM (D_NONE+6) - -/* internal only */ -#define D_SIZE (D_NONE+40) -#define D_PCREL (D_NONE+41) -#define D_GOTOFF (D_NONE+42) // R_ARM_GOTOFF -#define D_PLT0 (D_NONE+43) // R_ARM_PLT32, 1st inst: add ip, pc, #0xNN00000 -#define D_PLT1 (D_NONE+44) // R_ARM_PLT32, 2nd inst: add ip, ip, #0xNN000 -#define D_PLT2 (D_NONE+45) // R_ARM_PLT32, 3rd inst: ldr pc, [ip, #0xNNN]! -#define D_CALL (D_NONE+46) // R_ARM_PLT32/R_ARM_CALL/R_ARM_JUMP24, bl xxxxx or b yyyyy -#define D_TLS (D_NONE+47) // R_ARM_TLS_LE32 + D_EXTERN = (D_NONE+3), + D_STATIC = (D_NONE+4), + D_AUTO = (D_NONE+5), + D_PARAM = (D_NONE+6), +}; /* * this is the ranlib header */ #define SYMDEF "__.GOSYMDEF" - -/* - * this is the simulated IEEE floating point - */ -typedef struct ieee Ieee; -struct ieee -{ - int32 l; /* contains ls-man 0xffffffff */ - int32 h; /* contains sign 0x80000000 - exp 0x7ff00000 - ms-man 0x000fffff */ -}; diff --git a/src/cmd/5l/asm.c b/src/cmd/5l/asm.c index 33cdf8096..5e9267b5b 100644 --- a/src/cmd/5l/asm.c +++ b/src/cmd/5l/asm.c @@ -35,43 +35,26 @@ #include "../ld/elf.h" #include "../ld/dwarf.h" -static Prog *PP; char linuxdynld[] = "/lib/ld-linux.so.3"; // 2 for OABI, 3 for EABI char freebsddynld[] = "/usr/libexec/ld-elf.so.1"; char openbsddynld[] = "XXX"; char netbsddynld[] = "/libexec/ld.elf_so"; char dragonflydynld[] = "XXX"; - -int32 -entryvalue(void) -{ - char *a; - Sym *s; - - a = INITENTRY; - if(*a >= '0' && *a <= '9') - return atolwhex(a); - s = lookup(a, 0); - if(s->type == 0) - return INITTEXT; - if(s->type != STEXT) - diag("entry not text: %s", s->name); - return s->value; -} +char solarisdynld[] = "XXX"; static int needlib(char *name) { char *p; - Sym *s; + LSym *s; if(*name == '\0') return 0; /* reuse hash code in symbol table */ p = smprint(".dynlib.%s", name); - s = lookup(p, 0); + s = linklookup(ctxt, p, 0); free(p); if(s->type == 0) { s->type = 100; // avoid SDATA, etc. @@ -82,9 +65,9 @@ needlib(char *name) int nelfsym = 1; -static void addpltsym(Sym*); -static void addgotsym(Sym*); -static void addgotsyminternal(Sym*); +static void addpltsym(Link*, LSym*); +static void addgotsym(Link*, LSym*); +static void addgotsyminternal(Link*, LSym*); // Preserve highest 8 bits of a, and do addition to lower 24-bit // of a and b; used to adjust ARM branch intruction's target @@ -95,19 +78,19 @@ braddoff(int32 a, int32 b) } void -adddynrela(Sym *rel, Sym *s, Reloc *r) +adddynrela(LSym *rel, LSym *s, Reloc *r) { - addaddrplus(rel, s, r->off); - adduint32(rel, R_ARM_RELATIVE); + addaddrplus(ctxt, rel, s, r->off); + adduint32(ctxt, rel, R_ARM_RELATIVE); } void -adddynrel(Sym *s, Reloc *r) +adddynrel(LSym *s, Reloc *r) { - Sym *targ, *rel; + LSym *targ, *rel; targ = r->sym; - cursym = s; + ctxt->cursym = s; switch(r->type) { default: @@ -119,10 +102,10 @@ adddynrel(Sym *s, Reloc *r) // Handle relocations found in ELF object files. case 256 + R_ARM_PLT32: - r->type = D_CALL; + r->type = R_CALLARM; if(targ->type == SDYNIMPORT) { - addpltsym(targ); - r->sym = lookup(".plt", 0); + addpltsym(ctxt, targ); + r->sym = linklookup(ctxt, ".plt", 0); r->add = braddoff(r->add, targ->plt / 4); } return; @@ -134,54 +117,54 @@ adddynrel(Sym *s, Reloc *r) case 256 + R_ARM_GOT32: // R_ARM_GOT_BREL if(targ->type != SDYNIMPORT) { - addgotsyminternal(targ); + addgotsyminternal(ctxt, targ); } else { - addgotsym(targ); + addgotsym(ctxt, targ); } - r->type = D_CONST; // write r->add during relocsym + r->type = R_CONST; // write r->add during relocsym r->sym = S; r->add += targ->got; return; case 256 + R_ARM_GOT_PREL: // GOT(S) + A - P if(targ->type != SDYNIMPORT) { - addgotsyminternal(targ); + addgotsyminternal(ctxt, targ); } else { - addgotsym(targ); + addgotsym(ctxt, targ); } - r->type = D_PCREL; - r->sym = lookup(".got", 0); + r->type = R_PCREL; + r->sym = linklookup(ctxt, ".got", 0); r->add += targ->got + 4; return; case 256 + R_ARM_GOTOFF: // R_ARM_GOTOFF32 - r->type = D_GOTOFF; + r->type = R_GOTOFF; return; case 256 + R_ARM_GOTPC: // R_ARM_BASE_PREL - r->type = D_PCREL; - r->sym = lookup(".got", 0); + r->type = R_PCREL; + r->sym = linklookup(ctxt, ".got", 0); r->add += 4; return; case 256 + R_ARM_CALL: - r->type = D_CALL; + r->type = R_CALLARM; if(targ->type == SDYNIMPORT) { - addpltsym(targ); - r->sym = lookup(".plt", 0); + addpltsym(ctxt, targ); + r->sym = linklookup(ctxt, ".plt", 0); r->add = braddoff(r->add, targ->plt / 4); } return; case 256 + R_ARM_REL32: // R_ARM_REL32 - r->type = D_PCREL; + r->type = R_PCREL; r->add += 4; return; case 256 + R_ARM_ABS32: if(targ->type == SDYNIMPORT) diag("unexpected R_ARM_ABS32 relocation for dynamic symbol %s", targ->name); - r->type = D_ADDR; + r->type = R_ADDR; return; case 256 + R_ARM_V4BX: @@ -195,10 +178,10 @@ adddynrel(Sym *s, Reloc *r) case 256 + R_ARM_PC24: case 256 + R_ARM_JUMP24: - r->type = D_CALL; + r->type = R_CALLARM; if(targ->type == SDYNIMPORT) { - addpltsym(targ); - r->sym = lookup(".plt", 0); + addpltsym(ctxt, targ); + r->sym = linklookup(ctxt, ".plt", 0); r->add = braddoff(r->add, targ->plt / 4); } return; @@ -209,28 +192,28 @@ adddynrel(Sym *s, Reloc *r) return; switch(r->type) { - case D_PCREL: - addpltsym(targ); - r->sym = lookup(".plt", 0); + case R_CALLARM: + addpltsym(ctxt, targ); + r->sym = linklookup(ctxt, ".plt", 0); r->add = targ->plt; return; - case D_ADDR: + case R_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_ARM_GLOB_DAT)); // we need a S + A dynmic reloc - r->type = D_CONST; // write r->add during relocsym + adddynsym(ctxt, targ); + rel = linklookup(ctxt, ".rel", 0); + addaddrplus(ctxt, rel, s, r->off); + adduint32(ctxt, rel, ELF32_R_INFO(targ->dynid, R_ARM_GLOB_DAT)); // we need a S + A dynmic reloc + r->type = R_CONST; // write r->add during relocsym r->sym = S; return; } break; } - cursym = s; + ctxt->cursym = s; diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type); } @@ -246,21 +229,21 @@ elfreloc1(Reloc *r, vlong sectoff) default: return -1; - case D_ADDR: + case R_ADDR: if(r->siz == 4) LPUT(R_ARM_ABS32 | elfsym<<8); else return -1; break; - case D_PCREL: + case R_PCREL: if(r->siz == 4) LPUT(R_ARM_REL32 | elfsym<<8); else return -1; break; - case D_CALL: + case R_CALLARM: if(r->siz == 4) { if((r->add & 0xff000000) == 0xeb000000) // BL LPUT(R_ARM_CALL | elfsym<<8); @@ -270,7 +253,7 @@ elfreloc1(Reloc *r, vlong sectoff) return -1; break; - case D_TLS: + case R_TLS: if(r->siz == 4) { if(flag_shared) LPUT(R_ARM_TLS_IE32 | elfsym<<8); @@ -287,26 +270,26 @@ elfreloc1(Reloc *r, vlong sectoff) void elfsetupplt(void) { - Sym *plt, *got; + LSym *plt, *got; - plt = lookup(".plt", 0); - got = lookup(".got.plt", 0); + plt = linklookup(ctxt, ".plt", 0); + got = linklookup(ctxt, ".got.plt", 0); if(plt->size == 0) { // str lr, [sp, #-4]! - adduint32(plt, 0xe52de004); + adduint32(ctxt, plt, 0xe52de004); // ldr lr, [pc, #4] - adduint32(plt, 0xe59fe004); + adduint32(ctxt, plt, 0xe59fe004); // add lr, pc, lr - adduint32(plt, 0xe08fe00e); + adduint32(ctxt, plt, 0xe08fe00e); // ldr pc, [lr, #8]! - adduint32(plt, 0xe5bef008); + adduint32(ctxt, plt, 0xe5bef008); // .word &GLOBAL_OFFSET_TABLE[0] - . - addpcrelplus(plt, got, 4); + addpcrelplus(ctxt, plt, got, 4); // the first .plt entry requires 3 .plt.got entries - adduint32(got, 0); - adduint32(got, 0); - adduint32(got, 0); + adduint32(ctxt, got, 0); + adduint32(ctxt, got, 0); + adduint32(ctxt, got, 0); } } @@ -321,13 +304,13 @@ machoreloc1(Reloc *r, vlong sectoff) int -archreloc(Reloc *r, Sym *s, vlong *val) +archreloc(Reloc *r, LSym *s, vlong *val) { - Sym *rs; + LSym *rs; if(linkmode == LinkExternal) { switch(r->type) { - case D_CALL: + case R_CALLARM: r->done = 0; // set up addend for eventual relocation via outer symbol. @@ -352,29 +335,29 @@ archreloc(Reloc *r, Sym *s, vlong *val) return -1; } switch(r->type) { - case D_CONST: + case R_CONST: *val = r->add; return 0; - case D_GOTOFF: - *val = symaddr(r->sym) + r->add - symaddr(lookup(".got", 0)); + case R_GOTOFF: + *val = symaddr(r->sym) + r->add - symaddr(linklookup(ctxt, ".got", 0)); return 0; // The following three arch specific relocations are only for generation of // Linux/ARM ELF's PLT entry (3 assembler instruction) - case D_PLT0: // add ip, pc, #0xXX00000 - if (symaddr(lookup(".got.plt", 0)) < symaddr(lookup(".plt", 0))) + case R_PLT0: // add ip, pc, #0xXX00000 + if (symaddr(linklookup(ctxt, ".got.plt", 0)) < symaddr(linklookup(ctxt, ".plt", 0))) diag(".got.plt should be placed after .plt section."); *val = 0xe28fc600U + - (0xff & ((uint32)(symaddr(r->sym) - (symaddr(lookup(".plt", 0)) + r->off) + r->add) >> 20)); + (0xff & ((uint32)(symaddr(r->sym) - (symaddr(linklookup(ctxt, ".plt", 0)) + r->off) + r->add) >> 20)); return 0; - case D_PLT1: // add ip, ip, #0xYY000 + case R_PLT1: // add ip, ip, #0xYY000 *val = 0xe28cca00U + - (0xff & ((uint32)(symaddr(r->sym) - (symaddr(lookup(".plt", 0)) + r->off) + r->add + 4) >> 12)); + (0xff & ((uint32)(symaddr(r->sym) - (symaddr(linklookup(ctxt, ".plt", 0)) + r->off) + r->add + 4) >> 12)); return 0; - case D_PLT2: // ldr pc, [ip, #0xZZZ]! + case R_PLT2: // ldr pc, [ip, #0xZZZ]! *val = 0xe5bcf000U + - (0xfff & (uint32)(symaddr(r->sym) - (symaddr(lookup(".plt", 0)) + r->off) + r->add + 8)); + (0xfff & (uint32)(symaddr(r->sym) - (symaddr(linklookup(ctxt, ".plt", 0)) + r->off) + r->add + 8)); return 0; - case D_CALL: // bl XXXXXX or b YYYYYY + case R_CALLARM: // bl XXXXXX or b YYYYYY *val = braddoff((0xff000000U & (uint32)r->add), (0xffffff & (uint32) ((symaddr(r->sym) + ((uint32)r->add) * 4 - (s->value + r->off)) / 4))); @@ -384,7 +367,7 @@ archreloc(Reloc *r, Sym *s, vlong *val) } static Reloc * -addpltreloc(Sym *plt, Sym *got, Sym *sym, int typ) +addpltreloc(Link *ctxt, LSym *plt, LSym *got, LSym *sym, int typ) { Reloc *r; @@ -397,25 +380,25 @@ addpltreloc(Sym *plt, Sym *got, Sym *sym, int typ) plt->reachable = 1; plt->size += 4; - symgrow(plt, plt->size); + symgrow(ctxt, plt, plt->size); return r; } static void -addpltsym(Sym *s) +addpltsym(Link *ctxt, LSym *s) { - Sym *plt, *got, *rel; + LSym *plt, *got, *rel; if(s->plt >= 0) return; - adddynsym(s); + adddynsym(ctxt, s); if(iself) { - plt = lookup(".plt", 0); - got = lookup(".got.plt", 0); - rel = lookup(".rel.plt", 0); + plt = linklookup(ctxt, ".plt", 0); + got = linklookup(ctxt, ".got.plt", 0); + rel = linklookup(ctxt, ".rel.plt", 0); if(plt->size == 0) elfsetupplt(); @@ -424,34 +407,34 @@ addpltsym(Sym *s) // In theory, all GOT should point to the first PLT entry, // Linux/ARM's dynamic linker will do that for us, but FreeBSD/ARM's // dynamic linker won't, so we'd better do it ourselves. - addaddrplus(got, plt, 0); + addaddrplus(ctxt, got, plt, 0); // .plt entry, this depends on the .got entry s->plt = plt->size; - addpltreloc(plt, got, s, D_PLT0); // add lr, pc, #0xXX00000 - addpltreloc(plt, got, s, D_PLT1); // add lr, lr, #0xYY000 - addpltreloc(plt, got, s, D_PLT2); // ldr pc, [lr, #0xZZZ]! + addpltreloc(ctxt, plt, got, s, R_PLT0); // add lr, pc, #0xXX00000 + addpltreloc(ctxt, plt, got, s, R_PLT1); // add lr, lr, #0xYY000 + addpltreloc(ctxt, plt, got, s, R_PLT2); // ldr pc, [lr, #0xZZZ]! // rel - addaddrplus(rel, got, s->got); - adduint32(rel, ELF32_R_INFO(s->dynid, R_ARM_JUMP_SLOT)); + addaddrplus(ctxt, rel, got, s->got); + adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_ARM_JUMP_SLOT)); } else { diag("addpltsym: unsupported binary format"); } } static void -addgotsyminternal(Sym *s) +addgotsyminternal(Link *ctxt, LSym *s) { - Sym *got; + LSym *got; if(s->got >= 0) return; - got = lookup(".got", 0); + got = linklookup(ctxt, ".got", 0); s->got = got->size; - addaddrplus(got, s, 0); + addaddrplus(ctxt, got, s, 0); if(iself) { ; @@ -461,31 +444,31 @@ addgotsyminternal(Sym *s) } static void -addgotsym(Sym *s) +addgotsym(Link *ctxt, LSym *s) { - Sym *got, *rel; + LSym *got, *rel; if(s->got >= 0) return; - adddynsym(s); - got = lookup(".got", 0); + adddynsym(ctxt, s); + got = linklookup(ctxt, ".got", 0); s->got = got->size; - adduint32(got, 0); + adduint32(ctxt, got, 0); if(iself) { - rel = lookup(".rel", 0); - addaddrplus(rel, got, s->got); - adduint32(rel, ELF32_R_INFO(s->dynid, R_ARM_GLOB_DAT)); + rel = linklookup(ctxt, ".rel", 0); + addaddrplus(ctxt, rel, got, s->got); + adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_ARM_GLOB_DAT)); } else { diag("addgotsym: unsupported binary format"); } } void -adddynsym(Sym *s) +adddynsym(Link *ctxt, LSym *s) { - Sym *d; + LSym *d; int t; char *name; @@ -495,20 +478,20 @@ adddynsym(Sym *s) if(iself) { s->dynid = nelfsym++; - d = lookup(".dynsym", 0); + d = linklookup(ctxt, ".dynsym", 0); /* name */ name = s->extname; - adduint32(d, addstring(lookup(".dynstr", 0), name)); + adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name)); /* value */ if(s->type == SDYNIMPORT) - adduint32(d, 0); + adduint32(ctxt, d, 0); else - addaddr(d, s); + addaddr(ctxt, d, s); /* size */ - adduint32(d, 0); + adduint32(ctxt, d, 0); /* type */ t = STB_GLOBAL << 4; @@ -516,12 +499,12 @@ adddynsym(Sym *s) t |= STT_FUNC; else t |= STT_OBJECT; - adduint8(d, t); - adduint8(d, 0); + adduint8(ctxt, d, t); + adduint8(ctxt, d, 0); /* shndx */ if(s->type == SDYNIMPORT) - adduint16(d, SHN_UNDEF); + adduint16(ctxt, d, SHN_UNDEF); else { switch(s->type) { default: @@ -538,7 +521,7 @@ adddynsym(Sym *s) t = 14; break; } - adduint16(d, t); + adduint16(ctxt, d, t); } } else { diag("adddynsym: unsupported binary format"); @@ -548,39 +531,27 @@ adddynsym(Sym *s) void adddynlib(char *lib) { - Sym *s; + LSym *s; if(!needlib(lib)) return; if(iself) { - s = lookup(".dynstr", 0); + s = linklookup(ctxt, ".dynstr", 0); if(s->size == 0) addstring(s, ""); - elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib)); + elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib)); } else { diag("adddynlib: unsupported binary format"); } } -vlong -datoff(vlong 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 asmb(void) { - int32 t; uint32 symo; Section *sect; - Sym *sym; + LSym *sym; int i; if(debug['v']) @@ -627,13 +598,7 @@ asmb(void) default: if(iself) goto ElfSym; - case Hnoheader: - case Hrisc: - case Hixp1200: - case Hipaq: - debug['s'] = 1; - break; - case Hplan9x32: + case Hplan9: symo = HEADR+segtext.len+segdata.filelen; break; ElfSym: @@ -659,11 +624,11 @@ asmb(void) elfemitreloc(); } break; - case Hplan9x32: + case Hplan9: asmplan9sym(); cflush(); - sym = lookup("pclntab", 0); + sym = linklookup(ctxt, "pclntab", 0); if(sym != nil) { lcsize = sym->np; for(i=0; i < lcsize; i++) @@ -675,46 +640,14 @@ asmb(void) } } - cursym = nil; + ctxt->cursym = nil; if(debug['v']) Bprint(&bso, "%5.2f header\n", cputime()); Bflush(&bso); cseek(0L); switch(HEADTYPE) { default: - case Hnoheader: /* no header */ - break; - case Hrisc: /* aif for risc os */ - lputl(0xe1a00000); /* NOP - decompress code */ - lputl(0xe1a00000); /* NOP - relocation code */ - lputl(0xeb000000 + 12); /* BL - zero init code */ - lputl(0xeb000000 + - (entryvalue() - - INITTEXT - + HEADR - - 12 - - 8) / 4); /* BL - entry code */ - - lputl(0xef000011); /* SWI - exit code */ - lputl(segtext.filelen+HEADR); /* text size */ - lputl(segdata.filelen); /* data size */ - lputl(0); /* sym size */ - - lputl(segdata.len - segdata.filelen); /* bss size */ - lputl(0); /* sym type */ - lputl(INITTEXT-HEADR); /* text addr */ - lputl(0); /* workspace - ignored */ - - lputl(32); /* addr mode / data addr flag */ - lputl(0); /* data addr */ - for(t=0; t<2; t++) - lputl(0); /* reserved */ - - for(t=0; t<15; t++) - lputl(0xe1a00000); /* NOP - zero init code */ - lputl(0xe1a0f00e); /* B (R14) - zero init return */ - break; - case Hplan9x32: /* plan 9 */ + case Hplan9: /* plan 9 */ lput(0x647); /* magic */ lput(segtext.filelen); /* sizes */ lput(segdata.filelen); @@ -724,14 +657,6 @@ asmb(void) lput(0L); lput(lcsize); break; - case Hixp1200: /* boot for IXP1200 */ - break; - case Hipaq: /* boot for ipaq */ - lputl(0xe3300000); /* nop */ - lputl(0xe3300000); /* nop */ - lputl(0xe3300000); /* nop */ - lputl(0xe3300000); /* nop */ - break; case Hlinux: case Hfreebsd: case Hnetbsd: @@ -808,1224 +733,17 @@ nopstat(char *f, Count *c) (double)(c->outof - c->count)/c->outof); } -void -asmout(Prog *p, Optab *o, int32 *out, Sym *gmsym) -{ - int32 o1, o2, o3, o4, o5, o6, v; - int r, rf, rt, rt2; - Reloc *rel; - -PP = p; - o1 = 0; - o2 = 0; - o3 = 0; - o4 = 0; - o5 = 0; - o6 = 0; - armsize += o->size; -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); - prasm(p); - break; - - case 0: /* pseudo ops */ -if(debug['G']) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->name, p->from.sym->fnptr); - break; - - case 1: /* op R,[R],R */ - o1 = oprrr(p->as, p->scond); - rf = p->from.reg; - rt = p->to.reg; - r = p->reg; - if(p->to.type == D_NONE) - rt = 0; - if(p->as == AMOVB || p->as == AMOVH || p->as == AMOVW || p->as == AMVN) - r = 0; - else - if(r == NREG) - r = rt; - o1 |= rf | (r<<16) | (rt<<12); - break; - - case 2: /* movbu $I,[R],R */ - aclass(&p->from); - o1 = oprrr(p->as, p->scond); - o1 |= immrot(instoffset); - rt = p->to.reg; - r = p->reg; - if(p->to.type == D_NONE) - rt = 0; - if(p->as == AMOVW || p->as == AMVN) - r = 0; - else if(r == NREG) - r = rt; - o1 |= (r<<16) | (rt<<12); - break; - - case 3: /* add R<<[IR],[R],R */ - mov: - aclass(&p->from); - o1 = oprrr(p->as, p->scond); - o1 |= p->from.offset; - rt = p->to.reg; - r = p->reg; - if(p->to.type == D_NONE) - rt = 0; - if(p->as == AMOVW || p->as == AMVN) - r = 0; - else if(r == NREG) - r = rt; - o1 |= (r<<16) | (rt<<12); - break; - - case 4: /* add $I,[R],R */ - aclass(&p->from); - o1 = oprrr(AADD, p->scond); - o1 |= immrot(instoffset); - r = p->from.reg; - if(r == NREG) - r = o->param; - o1 |= r << 16; - o1 |= p->to.reg << 12; - break; - - case 5: /* bra s */ - o1 = opbra(p->as, p->scond); - v = -8; - if(p->to.sym != S && p->to.sym->type != 0) { - rel = addrel(cursym); - rel->off = pc - cursym->value; - rel->siz = 4; - rel->sym = p->to.sym; - rel->add = o1 | ((v >> 2) & 0xffffff); - rel->type = D_CALL; - break; - } - if(p->cond != P) - v = (p->cond->pc - pc) - 8; - o1 |= (v >> 2) & 0xffffff; - break; - - case 6: /* b ,O(R) -> add $O,R,PC */ - aclass(&p->to); - o1 = oprrr(AADD, p->scond); - o1 |= immrot(instoffset); - o1 |= p->to.reg << 16; - o1 |= REGPC << 12; - break; - - case 7: /* bl (R) -> blx R */ - aclass(&p->to); - if(instoffset != 0) - diag("%P: doesn't support BL offset(REG) where offset != 0", p); - o1 = oprrr(ABL, p->scond); - o1 |= p->to.reg; - break; - - case 8: /* sll $c,[R],R -> mov (R<<$c),R */ - aclass(&p->from); - o1 = oprrr(p->as, p->scond); - r = p->reg; - if(r == NREG) - r = p->to.reg; - o1 |= r; - o1 |= (instoffset&31) << 7; - o1 |= p->to.reg << 12; - break; - - case 9: /* sll R,[R],R -> mov (R<as, p->scond); - r = p->reg; - if(r == NREG) - r = p->to.reg; - o1 |= r; - o1 |= (p->from.reg << 8) | (1<<4); - o1 |= p->to.reg << 12; - break; - - case 10: /* swi [$con] */ - o1 = oprrr(p->as, p->scond); - if(p->to.type != D_NONE) { - aclass(&p->to); - o1 |= instoffset & 0xffffff; - } - break; - - case 11: /* word */ - aclass(&p->to); - o1 = instoffset; - if(p->to.sym != S) { - rel = addrel(cursym); - rel->off = pc - cursym->value; - rel->siz = 4; - rel->sym = p->to.sym; - rel->add = p->to.offset; - if(rel->sym == gmsym) { - rel->type = D_TLS; - if(flag_shared) - rel->add += pc - p->pcrel->pc - 8 - rel->siz; - rel->xadd = rel->add; - rel->xsym = rel->sym; - } else if(flag_shared) { - rel->type = D_PCREL; - rel->add += pc - p->pcrel->pc - 8; - } else - rel->type = D_ADDR; - o1 = 0; - } - break; - - case 12: /* movw $lcon, reg */ - o1 = omvl(p, &p->from, p->to.reg); - if(o->flag & LPCREL) { - o2 = oprrr(AADD, p->scond) | p->to.reg | REGPC << 16 | p->to.reg << 12; - } - break; - - case 13: /* op $lcon, [R], R */ - o1 = omvl(p, &p->from, REGTMP); - if(!o1) - break; - o2 = oprrr(p->as, p->scond); - o2 |= REGTMP; - r = p->reg; - if(p->as == AMOVW || p->as == AMVN) - r = 0; - else if(r == NREG) - r = p->to.reg; - o2 |= r << 16; - if(p->to.type != D_NONE) - o2 |= p->to.reg << 12; - break; - - case 14: /* movb/movbu/movh/movhu R,R */ - o1 = oprrr(ASLL, p->scond); - - if(p->as == AMOVBU || p->as == AMOVHU) - o2 = oprrr(ASRL, p->scond); - else - o2 = oprrr(ASRA, p->scond); - - r = p->to.reg; - o1 |= (p->from.reg)|(r<<12); - o2 |= (r)|(r<<12); - if(p->as == AMOVB || p->as == AMOVBS || p->as == AMOVBU) { - o1 |= (24<<7); - o2 |= (24<<7); - } else { - o1 |= (16<<7); - o2 |= (16<<7); - } - break; - - case 15: /* mul r,[r,]r */ - o1 = oprrr(p->as, p->scond); - rf = p->from.reg; - rt = p->to.reg; - r = p->reg; - if(r == NREG) - r = rt; - if(rt == r) { - r = rf; - rf = rt; - } - if(0) - if(rt == r || rf == REGPC || r == REGPC || rt == REGPC) { - diag("bad registers in MUL"); - prasm(p); - } - o1 |= (rf<<8) | r | (rt<<16); - break; - - - case 16: /* div r,[r,]r */ - o1 = 0xf << 28; - o2 = 0; - break; - - case 17: - o1 = oprrr(p->as, p->scond); - rf = p->from.reg; - rt = p->to.reg; - rt2 = p->to.offset; - r = p->reg; - o1 |= (rf<<8) | r | (rt<<16) | (rt2<<12); - break; - - case 20: /* mov/movb/movbu R,O(R) */ - aclass(&p->to); - r = p->to.reg; - if(r == NREG) - r = o->param; - o1 = osr(p->as, p->from.reg, instoffset, r, p->scond); - break; - - case 21: /* mov/movbu O(R),R -> lr */ - aclass(&p->from); - r = p->from.reg; - if(r == NREG) - r = o->param; - o1 = olr(instoffset, r, p->to.reg, p->scond); - if(p->as != AMOVW) - o1 |= 1<<22; - break; - - case 30: /* mov/movb/movbu R,L(R) */ - o1 = omvl(p, &p->to, REGTMP); - if(!o1) - break; - r = p->to.reg; - if(r == NREG) - r = o->param; - o2 = osrr(p->from.reg, REGTMP,r, p->scond); - if(p->as != AMOVW) - o2 |= 1<<22; - break; - - case 31: /* mov/movbu L(R),R -> lr[b] */ - o1 = omvl(p, &p->from, REGTMP); - if(!o1) - break; - r = p->from.reg; - if(r == NREG) - r = o->param; - o2 = olrr(REGTMP,r, p->to.reg, p->scond); - if(p->as == AMOVBU || p->as == AMOVBS || p->as == AMOVB) - o2 |= 1<<22; - break; - - case 34: /* mov $lacon,R */ - o1 = omvl(p, &p->from, REGTMP); - if(!o1) - break; - - o2 = oprrr(AADD, p->scond); - o2 |= REGTMP; - r = p->from.reg; - if(r == NREG) - r = o->param; - o2 |= r << 16; - if(p->to.type != D_NONE) - o2 |= p->to.reg << 12; - break; - - case 35: /* mov PSR,R */ - o1 = (2<<23) | (0xf<<16) | (0<<0); - o1 |= (p->scond & C_SCOND) << 28; - o1 |= (p->from.reg & 1) << 22; - o1 |= p->to.reg << 12; - break; - - case 36: /* mov R,PSR */ - o1 = (2<<23) | (0x29f<<12) | (0<<4); - if(p->scond & C_FBIT) - o1 ^= 0x010 << 12; - o1 |= (p->scond & C_SCOND) << 28; - o1 |= (p->to.reg & 1) << 22; - o1 |= p->from.reg << 0; - break; - - case 37: /* mov $con,PSR */ - aclass(&p->from); - o1 = (2<<23) | (0x29f<<12) | (0<<4); - if(p->scond & C_FBIT) - o1 ^= 0x010 << 12; - o1 |= (p->scond & C_SCOND) << 28; - o1 |= immrot(instoffset); - o1 |= (p->to.reg & 1) << 22; - o1 |= p->from.reg << 0; - break; - - case 38: /* movm $con,oreg -> stm */ - o1 = (0x4 << 25); - o1 |= p->from.offset & 0xffff; - o1 |= p->to.reg << 16; - aclass(&p->to); - goto movm; - - case 39: /* movm oreg,$con -> ldm */ - o1 = (0x4 << 25) | (1 << 20); - o1 |= p->to.offset & 0xffff; - o1 |= p->from.reg << 16; - aclass(&p->from); - movm: - if(instoffset != 0) - diag("offset must be zero in MOVM"); - o1 |= (p->scond & C_SCOND) << 28; - if(p->scond & C_PBIT) - o1 |= 1 << 24; - if(p->scond & C_UBIT) - o1 |= 1 << 23; - if(p->scond & C_SBIT) - o1 |= 1 << 22; - if(p->scond & C_WBIT) - o1 |= 1 << 21; - break; - - case 40: /* swp oreg,reg,reg */ - aclass(&p->from); - if(instoffset != 0) - diag("offset must be zero in SWP"); - o1 = (0x2<<23) | (0x9<<4); - if(p->as != ASWPW) - o1 |= 1 << 22; - o1 |= p->from.reg << 16; - o1 |= p->reg << 0; - o1 |= p->to.reg << 12; - o1 |= (p->scond & C_SCOND) << 28; - break; - - case 41: /* rfe -> movm.s.w.u 0(r13),[r15] */ - o1 = 0xe8fd8000; - break; - - case 50: /* floating point store */ - v = regoff(&p->to); - r = p->to.reg; - if(r == NREG) - r = o->param; - o1 = ofsr(p->as, p->from.reg, v, r, p->scond, p); - break; - - case 51: /* floating point load */ - v = regoff(&p->from); - r = p->from.reg; - if(r == NREG) - r = o->param; - o1 = ofsr(p->as, p->to.reg, v, r, p->scond, p) | (1<<20); - break; - - case 52: /* floating point store, int32 offset UGLY */ - o1 = omvl(p, &p->to, REGTMP); - if(!o1) - break; - r = p->to.reg; - if(r == NREG) - r = o->param; - o2 = oprrr(AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r; - o3 = ofsr(p->as, p->from.reg, 0, REGTMP, p->scond, p); - break; - - case 53: /* floating point load, int32 offset UGLY */ - o1 = omvl(p, &p->from, REGTMP); - if(!o1) - break; - r = p->from.reg; - if(r == NREG) - r = o->param; - o2 = oprrr(AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r; - o3 = ofsr(p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20); - break; - - case 54: /* floating point arith */ - o1 = oprrr(p->as, p->scond); - rf = p->from.reg; - rt = p->to.reg; - r = p->reg; - if(r == NREG) { - r = rt; - if(p->as == AMOVF || p->as == AMOVD || p->as == ASQRTF || p->as == ASQRTD || p->as == AABSF || p->as == AABSD) - r = 0; - } - o1 |= rf | (r<<16) | (rt<<12); - break; - - case 56: /* move to FP[CS]R */ - o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4); - o1 |= ((p->to.reg+1)<<21) | (p->from.reg << 12); - break; - - case 57: /* move from FP[CS]R */ - o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4); - o1 |= ((p->from.reg+1)<<21) | (p->to.reg<<12) | (1<<20); - break; - case 58: /* movbu R,R */ - o1 = oprrr(AAND, p->scond); - o1 |= immrot(0xff); - rt = p->to.reg; - r = p->from.reg; - if(p->to.type == D_NONE) - rt = 0; - if(r == NREG) - r = rt; - o1 |= (r<<16) | (rt<<12); - break; - - case 59: /* movw/bu R< ldr indexed */ - if(p->from.reg == NREG) { - if(p->as != AMOVW) - diag("byte MOV from shifter operand"); - goto mov; - } - if(p->from.offset&(1<<4)) - diag("bad shift in LDR"); - o1 = olrr(p->from.offset, p->from.reg, p->to.reg, p->scond); - if(p->as == AMOVBU) - o1 |= 1<<22; - break; - - case 60: /* movb R(R),R -> ldrsb indexed */ - if(p->from.reg == NREG) { - diag("byte MOV from shifter operand"); - goto mov; - } - if(p->from.offset&(~0xf)) - diag("bad shift in LDRSB"); - o1 = olhrr(p->from.offset, p->from.reg, p->to.reg, p->scond); - o1 ^= (1<<5)|(1<<6); - break; - - case 61: /* movw/b/bu R,R<<[IR](R) -> str indexed */ - if(p->to.reg == NREG) - diag("MOV to shifter operand"); - o1 = osrr(p->from.reg, p->to.offset, p->to.reg, p->scond); - if(p->as == AMOVB || p->as == AMOVBS || p->as == AMOVBU) - o1 |= 1<<22; - break; - - case 62: /* case R -> movw R<<2(PC),PC */ - if(o->flag & LPCREL) { - o1 = oprrr(AADD, p->scond) | immrot(1) | p->from.reg << 16 | REGTMP << 12; - o2 = olrr(REGTMP, REGPC, REGTMP, p->scond); - o2 |= 2<<7; - o3 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGPC << 12; - } else { - o1 = olrr(p->from.reg, REGPC, REGPC, p->scond); - o1 |= 2<<7; - } - break; - - case 63: /* bcase */ - if(p->cond != P) { - rel = addrel(cursym); - rel->off = pc - cursym->value; - rel->siz = 4; - if(p->to.sym != S && p->to.sym->type != 0) { - rel->sym = p->to.sym; - rel->add = p->to.offset; - } else { - rel->sym = cursym; - rel->add = p->cond->pc - cursym->value; - } - if(o->flag & LPCREL) { - rel->type = D_PCREL; - rel->add += pc - p->pcrel->pc - 16 + rel->siz; - } else - rel->type = D_ADDR; - o1 = 0; - } - break; - - /* reloc ops */ - case 64: /* mov/movb/movbu R,addr */ - o1 = omvl(p, &p->to, REGTMP); - if(!o1) - break; - o2 = osr(p->as, p->from.reg, 0, REGTMP, p->scond); - if(o->flag & LPCREL) { - o3 = o2; - o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; - } - break; - - case 65: /* mov/movbu addr,R */ - o1 = omvl(p, &p->from, REGTMP); - if(!o1) - break; - o2 = olr(0, REGTMP, p->to.reg, p->scond); - if(p->as == AMOVBU || p->as == AMOVBS || p->as == AMOVB) - o2 |= 1<<22; - if(o->flag & LPCREL) { - o3 = o2; - o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; - } - break; - - case 68: /* floating point store -> ADDR */ - o1 = omvl(p, &p->to, REGTMP); - if(!o1) - break; - o2 = ofsr(p->as, p->from.reg, 0, REGTMP, p->scond, p); - if(o->flag & LPCREL) { - o3 = o2; - o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; - } - break; - - case 69: /* floating point load <- ADDR */ - o1 = omvl(p, &p->from, REGTMP); - if(!o1) - break; - o2 = ofsr(p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20); - if(o->flag & LPCREL) { - o3 = o2; - o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; - } - break; - - /* ArmV4 ops: */ - case 70: /* movh/movhu R,O(R) -> strh */ - aclass(&p->to); - r = p->to.reg; - if(r == NREG) - r = o->param; - o1 = oshr(p->from.reg, instoffset, r, p->scond); - break; - case 71: /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */ - aclass(&p->from); - r = p->from.reg; - if(r == NREG) - r = o->param; - o1 = olhr(instoffset, r, p->to.reg, p->scond); - if(p->as == AMOVB || p->as == AMOVBS) - o1 ^= (1<<5)|(1<<6); - else if(p->as == AMOVH || p->as == AMOVHS) - o1 ^= (1<<6); - break; - case 72: /* movh/movhu R,L(R) -> strh */ - o1 = omvl(p, &p->to, REGTMP); - if(!o1) - break; - r = p->to.reg; - if(r == NREG) - r = o->param; - o2 = oshrr(p->from.reg, REGTMP,r, p->scond); - break; - case 73: /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */ - o1 = omvl(p, &p->from, REGTMP); - if(!o1) - break; - r = p->from.reg; - if(r == NREG) - r = o->param; - o2 = olhrr(REGTMP, r, p->to.reg, p->scond); - if(p->as == AMOVB || p->as == AMOVBS) - o2 ^= (1<<5)|(1<<6); - else if(p->as == AMOVH || p->as == AMOVHS) - o2 ^= (1<<6); - break; - case 74: /* bx $I */ - diag("ABX $I"); - break; - case 75: /* bx O(R) */ - aclass(&p->to); - if(instoffset != 0) - diag("non-zero offset in ABX"); -/* - o1 = oprrr(AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR - o2 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | p->to.reg; // BX R -*/ - // p->to.reg may be REGLINK - o1 = oprrr(AADD, p->scond); - 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 - o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP; // BX Rtmp - break; - case 76: /* bx O(R) when returning from fn*/ - diag("ABXRET"); - break; - case 77: /* ldrex oreg,reg */ - aclass(&p->from); - if(instoffset != 0) - diag("offset must be zero in LDREX"); - o1 = (0x19<<20) | (0xf9f); - o1 |= p->from.reg << 16; - o1 |= p->to.reg << 12; - o1 |= (p->scond & C_SCOND) << 28; - break; - case 78: /* strex reg,oreg,reg */ - aclass(&p->from); - if(instoffset != 0) - diag("offset must be zero in STREX"); - o1 = (0x18<<20) | (0xf90); - o1 |= p->from.reg << 16; - o1 |= p->reg << 0; - o1 |= p->to.reg << 12; - o1 |= (p->scond & C_SCOND) << 28; - break; - case 80: /* fmov zfcon,freg */ - if(p->as == AMOVD) { - o1 = 0xeeb00b00; // VMOV imm 64 - o2 = oprrr(ASUBD, p->scond); - } else { - o1 = 0x0eb00a00; // VMOV imm 32 - o2 = oprrr(ASUBF, p->scond); - } - v = 0x70; // 1.0 - r = p->to.reg; - - // movf $1.0, r - o1 |= (p->scond & C_SCOND) << 28; - o1 |= r << 12; - o1 |= (v&0xf) << 0; - o1 |= (v&0xf0) << 12; - - // subf r,r,r - o2 |= r | (r<<16) | (r<<12); - 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; - case 90: /* tst reg */ - o1 = oprrr(ACMP+AEND, p->scond); - o1 |= p->from.reg<<16; - break; - case 91: /* ldrexd oreg,reg */ - aclass(&p->from); - if(instoffset != 0) - diag("offset must be zero in LDREX"); - o1 = (0x1b<<20) | (0xf9f); - o1 |= p->from.reg << 16; - o1 |= p->to.reg << 12; - o1 |= (p->scond & C_SCOND) << 28; - break; - case 92: /* strexd reg,oreg,reg */ - aclass(&p->from); - if(instoffset != 0) - diag("offset must be zero in STREX"); - o1 = (0x1a<<20) | (0xf90); - o1 |= p->from.reg << 16; - o1 |= p->reg << 0; - o1 |= p->to.reg << 12; - o1 |= (p->scond & C_SCOND) << 28; - break; - case 93: /* movb/movh/movhu addr,R -> ldrsb/ldrsh/ldrh */ - o1 = omvl(p, &p->from, REGTMP); - if(!o1) - break; - o2 = olhr(0, REGTMP, p->to.reg, p->scond); - if(p->as == AMOVB || p->as == AMOVBS) - o2 ^= (1<<5)|(1<<6); - else if(p->as == AMOVH || p->as == AMOVHS) - o2 ^= (1<<6); - if(o->flag & LPCREL) { - o3 = o2; - o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; - } - break; - case 94: /* movh/movhu R,addr -> strh */ - o1 = omvl(p, &p->to, REGTMP); - if(!o1) - break; - o2 = oshr(p->from.reg, 0, REGTMP, p->scond); - if(o->flag & LPCREL) { - o3 = o2; - o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; - } - break; - case 95: /* PLD off(reg) */ - o1 = 0xf5d0f000; - o1 |= p->from.reg << 16; - if(p->from.offset < 0) { - o1 &= ~(1 << 23); - o1 |= (-p->from.offset) & 0xfff; - } else - o1 |= p->from.offset & 0xfff; - break; - case 96: /* UNDEF */ - // This is supposed to be something that stops execution. - // It's not supposed to be reached, ever, but if it is, we'd - // like to be able to tell how we got there. Assemble as - // 0xf7fabcfd which is guranteed to raise undefined instruction - // exception. - o1 = 0xf7fabcfd; - break; - case 97: /* CLZ Rm, Rd */ - o1 = oprrr(p->as, p->scond); - o1 |= p->to.reg << 12; - o1 |= p->from.reg; - break; - case 98: /* MULW{T,B} Rs, Rm, Rd */ - o1 = oprrr(p->as, p->scond); - o1 |= p->to.reg << 16; - o1 |= p->from.reg << 8; - o1 |= p->reg; - break; - case 99: /* MULAW{T,B} Rs, Rm, Rn, Rd */ - o1 = oprrr(p->as, p->scond); - o1 |= p->to.reg << 12; - o1 |= p->from.reg << 8; - o1 |= p->reg; - o1 |= p->to.offset << 16; - break; - } - - out[0] = o1; - out[1] = o2; - out[2] = o3; - out[3] = o4; - out[4] = o5; - out[5] = o6; - return; - -#ifdef NOTDEF - v = p->pc; - switch(o->size) { - default: - if(debug['a']) - Bprint(&bso, " %.8ux:\t\t%P\n", v, p); - break; - case 4: - if(debug['a']) - Bprint(&bso, " %.8ux: %.8ux\t%P\n", v, o1, p); - lputl(o1); - break; - case 8: - if(debug['a']) - Bprint(&bso, " %.8ux: %.8ux %.8ux%P\n", v, o1, o2, p); - lputl(o1); - lputl(o2); - break; - case 12: - if(debug['a']) - 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, " %.8ux: %.8ux %.8ux %.8ux %.8ux%P\n", - v, o1, o2, o3, o4, p); - lputl(o1); - lputl(o2); - lputl(o3); - lputl(o4); - break; - case 20: - if(debug['a']) - Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux%P\n", - v, o1, o2, o3, o4, o5, p); - lputl(o1); - lputl(o2); - lputl(o3); - lputl(o4); - lputl(o5); - break; - case 24: - if(debug['a']) - Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux %.8ux%P\n", - v, o1, o2, o3, o4, o5, o6, p); - lputl(o1); - lputl(o2); - lputl(o3); - lputl(o4); - lputl(o5); - lputl(o6); - break; - } -#endif -} - -int32 -oprrr(int a, int sc) -{ - int32 o; - - o = (sc & C_SCOND) << 28; - if(sc & C_SBIT) - o |= 1 << 20; - if(sc & (C_PBIT|C_WBIT)) - diag(".P/.W on dp instruction"); - switch(a) { - case AMULU: - case AMUL: return o | (0x0<<21) | (0x9<<4); - case AMULA: return o | (0x1<<21) | (0x9<<4); - case AMULLU: return o | (0x4<<21) | (0x9<<4); - case AMULL: return o | (0x6<<21) | (0x9<<4); - case AMULALU: return o | (0x5<<21) | (0x9<<4); - case AMULAL: return o | (0x7<<21) | (0x9<<4); - case AAND: return o | (0x0<<21); - case AEOR: return o | (0x1<<21); - case ASUB: return o | (0x2<<21); - case ARSB: return o | (0x3<<21); - case AADD: return o | (0x4<<21); - case AADC: return o | (0x5<<21); - case ASBC: return o | (0x6<<21); - case ARSC: return o | (0x7<<21); - case ATST: return o | (0x8<<21) | (1<<20); - case ATEQ: return o | (0x9<<21) | (1<<20); - case ACMP: return o | (0xa<<21) | (1<<20); - case ACMN: return o | (0xb<<21) | (1<<20); - case AORR: return o | (0xc<<21); - case AMOVB: - case AMOVH: - case AMOVW: return o | (0xd<<21); - case ABIC: return o | (0xe<<21); - case AMVN: return o | (0xf<<21); - case ASLL: return o | (0xd<<21) | (0<<5); - case ASRL: return o | (0xd<<21) | (1<<5); - case ASRA: return o | (0xd<<21) | (2<<5); - case ASWI: return o | (0xf<<24); - - 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 ASQRTD: return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xb<<8) | (0xc<<4); - case ASQRTF: return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xa<<8) | (0xc<<4); - case AABSD: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xb<<8) | (0xc<<4); - case AABSF: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xa<<8) | (0xc<<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); - case ACMP+AEND: // cmp imm - return o | (0x3<<24) | (0x5<<20); - - case ACLZ: - // CLZ doesn't support .S - return (o & (0xf<<28)) | (0x16f<<16) | (0xf1<<4); - - case AMULWT: - return (o & (0xf<<28)) | (0x12 << 20) | (0xe<<4); - case AMULWB: - return (o & (0xf<<28)) | (0x12 << 20) | (0xa<<4); - case AMULAWT: - return (o & (0xf<<28)) | (0x12 << 20) | (0xc<<4); - case AMULAWB: - return (o & (0xf<<28)) | (0x12 << 20) | (0x8<<4); - - case ABL: // BLX REG - return (o & (0xf<<28)) | (0x12fff3 << 4); - } - diag("bad rrr %d", a); - prasm(curp); - return 0; -} - -int32 -opbra(int a, int sc) -{ - - if(sc & (C_SBIT|C_PBIT|C_WBIT)) - diag(".S/.P/.W on bra instruction"); - sc &= C_SCOND; - if(a == ABL) - return (sc<<28)|(0x5<<25)|(0x1<<24); - if(sc != 0xe) - diag(".COND on bcond instruction"); - switch(a) { - case ABEQ: return (0x0<<28)|(0x5<<25); - case ABNE: return (0x1<<28)|(0x5<<25); - case ABCS: return (0x2<<28)|(0x5<<25); - case ABHS: return (0x2<<28)|(0x5<<25); - case ABCC: return (0x3<<28)|(0x5<<25); - case ABLO: return (0x3<<28)|(0x5<<25); - case ABMI: return (0x4<<28)|(0x5<<25); - case ABPL: return (0x5<<28)|(0x5<<25); - case ABVS: return (0x6<<28)|(0x5<<25); - case ABVC: return (0x7<<28)|(0x5<<25); - case ABHI: return (0x8<<28)|(0x5<<25); - case ABLS: return (0x9<<28)|(0x5<<25); - case ABGE: return (0xa<<28)|(0x5<<25); - case ABLT: return (0xb<<28)|(0x5<<25); - case ABGT: return (0xc<<28)|(0x5<<25); - case ABLE: return (0xd<<28)|(0x5<<25); - case AB: return (0xe<<28)|(0x5<<25); - } - diag("bad bra %A", a); - prasm(curp); - return 0; -} - int32 -olr(int32 v, int b, int r, int sc) -{ - int32 o; - - if(sc & C_SBIT) - diag(".S on LDR/STR instruction"); - o = (sc & C_SCOND) << 28; - if(!(sc & C_PBIT)) - o |= 1 << 24; - if(!(sc & C_UBIT)) - o |= 1 << 23; - if(sc & C_WBIT) - o |= 1 << 21; - 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) || v < 0) - diag("literal span too large: %d (R%d)\n%P", v, b, PP); - o |= v; - o |= b << 16; - o |= r << 12; - return o; -} - -int32 -olhr(int32 v, int b, int r, int sc) -{ - int32 o; - - if(sc & C_SBIT) - diag(".S on LDRH/STRH instruction"); - o = (sc & C_SCOND) << 28; - if(!(sc & C_PBIT)) - o |= 1 << 24; - if(sc & C_WBIT) - o |= 1 << 21; - o |= (1<<23) | (1<<20)|(0xb<<4); - if(v < 0) { - v = -v; - o ^= 1 << 23; - } - 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; - o |= r << 12; - return o; -} - -int32 -osr(int a, int r, int32 v, int b, int sc) -{ - int32 o; - - o = olr(v, b, r, sc) ^ (1<<20); - if(a != AMOVW) - o |= 1<<22; - return o; -} - -int32 -oshr(int r, int32 v, int b, int sc) -{ - int32 o; - - o = olhr(v, b, r, sc) ^ (1<<20); - return o; -} - - -int32 -osrr(int r, int i, int b, int sc) -{ - - return olr(i, b, r, sc) ^ ((1<<25) | (1<<20)); -} - -int32 -oshrr(int r, int i, int b, int sc) -{ - return olhr(i, b, r, sc) ^ ((1<<22) | (1<<20)); -} - -int32 -olrr(int i, int b, int r, int sc) -{ - - return olr(i, b, r, sc) ^ (1<<25); -} - -int32 -olhrr(int i, int b, int r, int sc) -{ - return olhr(i, b, r, sc) ^ (1<<22); -} - -int32 -ofsr(int a, int r, int32 v, int b, int sc, Prog *p) -{ - int32 o; - - if(sc & C_SBIT) - diag(".S on FLDR/FSTR instruction"); - o = (sc & C_SCOND) << 28; - if(!(sc & C_PBIT)) - o |= 1 << 24; - if(sc & C_WBIT) - o |= 1 << 21; - 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) || v < 0) - diag("literal span too large: %d\n%P", v, p); - o |= (v>>2) & 0xFF; - o |= b << 16; - o |= r << 12; - - switch(a) { - default: - diag("bad fst %A", a); - case AMOVD: - o |= 1 << 8; - case AMOVF: - break; - } - return o; -} - -int32 -omvl(Prog *p, Adr *a, int dr) -{ - int32 v, o1; - if(!p->cond) { - aclass(a); - v = immrot(~instoffset); - if(v == 0) { - diag("missing literal"); - prasm(p); - return 0; - } - o1 = oprrr(AMVN, p->scond&C_SCOND); - o1 |= v; - o1 |= dr << 12; - } else { - v = p->cond->pc - p->pc - 8; - o1 = olr(v, REGPC, dr, p->scond&C_SCOND); - } - return o1; -} - -int -chipzero(Ieee *e) -{ - // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions. - if(goarm < 7 || e->l != 0 || e->h != 0) - return -1; - return 0; -} - -int -chipfloat(Ieee *e) -{ - int n; - ulong h; - - // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions. - if(goarm < 7) - goto no; - - 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; +rnd(int32 v, int32 r) +{ + int32 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/5l/l.h b/src/cmd/5l/l.h index ae4b05ba1..761bc861a 100644 --- a/src/cmd/5l/l.h +++ b/src/cmd/5l/l.h @@ -31,6 +31,7 @@ #include #include #include +#include #include "5.out.h" enum @@ -38,6 +39,7 @@ enum thechar = '5', PtrSize = 4, IntSize = 4, + RegSize = 4, MaxAlign = 8, // max data alignment FuncAlign = 4 // single-instruction alignment }; @@ -51,167 +53,13 @@ enum #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; - #define P ((Prog*)0) -#define S ((Sym*)0) -#define TNAME (cursym?cursym->name:noname) - -struct Adr -{ - union - { - struct { - int32 u0offset; - int32 u0offset2; // argsize - } u0off; - char* u0sval; - Ieee u0ieee; - char* u0sbig; - } u0; - Sym* sym; - Sym* gotype; - char type; - char reg; - char name; - char class; -}; - -#define offset u0.u0off.u0offset -#define offset2 u0.u0off.u0offset2 -#define sval u0.u0sval -#define scon sval -#define ieee u0.u0ieee -#define sbig u0.u0sbig - -struct Reloc -{ - int32 off; - uchar siz; - uchar done; - int16 type; - int32 add; - int32 xadd; - Sym* sym; - Sym* xsym; -}; - -struct Prog -{ - Adr from; - Adr to; - union - { - int32 u0regused; - Prog* u0forwd; - } u0; - Prog* cond; - Prog* link; - Prog* pcrel; - int32 pc; - int32 line; - int32 spadj; - uchar mark; - uchar optab; - uchar as; - uchar scond; - uchar reg; - uchar align; // unused -}; - -#define regused u0.u0regused -#define forwd u0.u0forwd -#define datasize reg -#define textflag reg - -#define iscall(p) ((p)->as == ABL) - -struct Sym -{ - char* name; - char* extname; // name used in external object files - short type; - short version; - uchar dupok; - uchar reachable; - uchar cgoexport; - uchar leaf; - int32 dynid; - int32 plt; - int32 got; - int32 value; - int32 sig; - int32 size; - int32 align; // if non-zero, required alignment in bytes - int32 elfsym; - int32 locals; // size of stack frame locals area - int32 args; // size of stack frame incoming arguments area - uchar special; - uchar fnptr; // used as fn ptr - uchar stkcheck; - uchar hide; - Sym* hash; // in hash table - Sym* allsym; // in all symbol list - Sym* next; // in text or data list - Sym* sub; // in SSUB list - Sym* outer; // container of sub - Sym* gotype; - Sym* reachparent; - Sym* queue; - char* file; - char* dynimplib; - char* dynimpvers; - struct Section* sect; - struct Hist* hist; - - // STEXT - Auto* autom; - Prog* text; - - // SDATA, SBSS - uchar* p; - int32 np; - int32 maxp; - Reloc* r; - int32 nr; - int32 maxr; -}; +#define S ((LSym*)0) +#define TNAME (ctxt->cursym?ctxt->cursym->name:noname) #define SIGNINTERN (1729*325*1729) -struct Autom -{ - Sym* asym; - Auto* link; - int32 aoffset; - short type; - Sym* gotype; -}; -struct Optab -{ - char as; - uchar a1; - char a2; - uchar a3; - uchar type; - char size; - char param; - char flag; - uchar pcrelsiz; -}; -struct Oprang -{ - Optab* start; - Optab* stop; -}; +typedef struct Count Count; struct Count { int32 count; @@ -220,10 +68,17 @@ struct Count enum { - LFROM = 1<<0, - LTO = 1<<1, - LPOOL = 1<<2, - LPCREL = 1<<3, +/* mark flags */ + FOLL = 1<<0, + LABEL = 1<<1, + LEAF = 1<<2, + + STRINGSZ = 200, + MINSIZ = 64, + NENT = 100, + MAXIO = 8192, + MAXHIST = 40, /* limit of path elements for history symbols */ + MINLC = 4, C_NONE = 0, C_REG, @@ -260,7 +115,7 @@ enum C_HFOREG, C_SOREG, C_ROREG, - C_SROREG, /* both S and R */ + C_SROREG, /* both nil and R */ C_LOREG, C_PC, @@ -270,179 +125,45 @@ enum C_ADDR, /* reference to relocatable address */ C_GOK, - -/* mark flags */ - FOLL = 1<<0, - LABEL = 1<<1, - LEAF = 1<<2, - - STRINGSZ = 200, - MINSIZ = 64, - NENT = 100, - MAXIO = 8192, - MAXHIST = 40, /* limit of path elements for history symbols */ - MINLC = 4, }; #ifndef COFFCVT -EXTERN int32 HEADR; /* length of header */ -EXTERN int HEADTYPE; /* type of header */ -EXTERN int32 INITDAT; /* data location */ -EXTERN int32 INITRND; /* data round above text location */ -EXTERN int32 INITTEXT; /* text location */ -EXTERN char* INITENTRY; /* entry point */ EXTERN int32 autosize; -EXTERN Auto* curauto; -EXTERN Auto* curhist; -EXTERN Prog* curp; -EXTERN Sym* cursym; -EXTERN Sym* datap; +EXTERN LSym* datap; EXTERN int debug[128]; -EXTERN Sym* etextp; EXTERN char* noname; EXTERN Prog* lastp; EXTERN int32 lcsize; EXTERN char literal[32]; EXTERN int nerrors; EXTERN int32 instoffset; -EXTERN Opcross opcross[8]; -EXTERN Oprang oprange[ALAST]; -EXTERN char* outfile; -EXTERN int32 pc; -EXTERN uchar repop[ALAST]; -EXTERN char* interpreter; EXTERN char* rpath; EXTERN uint32 stroffset; EXTERN int32 symsize; -EXTERN Sym* textp; -EXTERN char xcmp[C_GOK+1][C_GOK+1]; -EXTERN Prog zprg; -EXTERN int dtype; -EXTERN int tlsoffset; EXTERN int armsize; -EXTERN int goarm; -EXTERN Sym* adrgotype; // type symbol on last Adr read -EXTERN Sym* fromgotype; // type symbol on last p->from read - -extern char* anames[]; -extern Optab optab[]; - -void addpool(Prog*, Adr*); -EXTERN Prog* blitrl; -EXTERN Prog* elitrl; -EXTERN int goarm; +#pragma varargck type "I" uint32* -void initdiv(void); -EXTERN Prog* prog_div; -EXTERN Prog* prog_divu; -EXTERN Prog* prog_mod; -EXTERN Prog* prog_modu; - -#pragma varargck type "A" int -#pragma varargck type "C" int -#pragma varargck type "D" Adr* -#pragma varargck type "I" uchar* -#pragma varargck type "N" Adr* -#pragma varargck type "P" Prog* -#pragma varargck type "S" char* -#pragma varargck type "Z" char* -#pragma varargck type "i" char* - -int Aconv(Fmt*); -int Cconv(Fmt*); -int Dconv(Fmt*); -int Iconv(Fmt*); -int Nconv(Fmt*); -int Oconv(Fmt*); -int Pconv(Fmt*); -int Sconv(Fmt*); -int aclass(Adr*); -void addhist(int32, int); -Prog* appendp(Prog*); +int Iconv(Fmt *fp); +void adddynlib(char *lib); +void adddynrel(LSym *s, Reloc *r); +void adddynrela(LSym *rel, LSym *s, Reloc *r); +void adddynsym(Link *ctxt, LSym *s); +int archreloc(Reloc *r, LSym *s, vlong *val); void asmb(void); -void asmout(Prog*, Optab*, int32*, Sym*); -int32 atolwhex(char*); -Prog* brloop(Prog*); -void buildop(void); -void buildrep(int, int); -void cflush(void); -int chipzero(Ieee*); -int chipfloat(Ieee*); -int cmp(int, int); -int compound(Prog*); -double cputime(void); -void diag(char*, ...); -void divsig(void); -void dodata(void); -void doprof1(void); -void doprof2(void); -int32 entryvalue(void); -void exchange(Prog*); -void follow(void); -void hputl(int); -int isnop(Prog*); +void cput(int32 c); +int elfreloc1(Reloc *r, vlong sectoff); +void elfsetupplt(void); +void hput(int32 l); void listinit(void); -Sym* lookup(char*, int); -void cput(int); -void hput(int32); -void lput(int32); -void lputb(int32); -void lputl(int32); -void* mysbrk(uint32); -void names(void); -void nocache(Prog*); -int ocmp(const void*, const void*); -int32 opirr(int); -Optab* oplook(Prog*); -int32 oprrr(int, int); -int32 olr(int32, int, int, int); -int32 olhr(int32, int, int, int); -int32 olrr(int, int, int, int); -int32 olhrr(int, int, int, int); -int32 osr(int, int, int32, int, int); -int32 oshr(int, int32, int, int); -int32 ofsr(int, int, int32, int, int, Prog*); -int32 osrr(int, int, int, int); -int32 oshrr(int, int, int, int); -int32 omvl(Prog*, Adr*, int); -void patch(void); -void prasm(Prog*); -void prepend(Prog*, Prog*); -Prog* prg(void); -int pseudo(Prog*); -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 vputb(uint64); -void vputl(uint64); -void wputb(uint16); -void wput(int32); -void wputl(ushort w); -void xdefine(char*, int, int32); +void lput(int32 l); +int machoreloc1(Reloc *r, vlong sectoff); +void main(int argc, char *argv[]); void noops(void); -int32 immrot(uint32); -int32 immaddr(int32); -int32 opbra(int, int); -int brextra(Prog*); -int isbranch(Prog*); -void doelf(void); -void dozerostk(void); // used by -Z - -vlong addaddr(Sym *s, Sym *t); -vlong addsize(Sym *s, Sym *t); -vlong addstring(Sym *s, char *str); -vlong adduint16(Sym *s, uint16 v); -vlong adduint32(Sym *s, uint32 v); -vlong adduint64(Sym *s, uint64 v); -vlong adduint8(Sym *s, uint8 v); -vlong adduintxx(Sym *s, uint64 v, int wid); +void nopstat(char *f, Count *c); +int32 rnd(int32 v, int32 r); +void wput(int32 l); /* Native is little-endian */ #define LPUT(a) lputl(a) diff --git a/src/cmd/5l/list.c b/src/cmd/5l/list.c index 7502a3b81..875fc3e6b 100644 --- a/src/cmd/5l/list.c +++ b/src/cmd/5l/list.c @@ -36,355 +36,10 @@ void listinit(void) { - - fmtinstall('A', Aconv); - fmtinstall('C', Cconv); - fmtinstall('D', Dconv); - fmtinstall('P', Pconv); - fmtinstall('S', Sconv); - fmtinstall('N', Nconv); - fmtinstall('O', Oconv); // C_type constants + listinit5(); fmtinstall('I', Iconv); } -void -prasm(Prog *p) -{ - print("%P\n", p); -} - -int -Pconv(Fmt *fp) -{ - Prog *p; - int a; - - p = va_arg(fp->args, Prog*); - curp = p; - a = p->as; - switch(a) { - default: - fmtprint(fp, "(%d)", p->line); - if(p->reg == NREG && p->as != AGLOBL) - fmtprint(fp, " %A%C %D,%D", - a, p->scond, &p->from, &p->to); - else - if(p->from.type != D_FREG) - fmtprint(fp, " %A%C %D,R%d,%D", - a, p->scond, &p->from, p->reg, &p->to); - else - fmtprint(fp, " %A%C %D,F%d,%D", - a, p->scond, &p->from, p->reg, &p->to); - break; - - case ASWPW: - case ASWPBU: - 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_: - fmtprint(fp, "(%d) %A%C %D/%d,%D", - p->line, a, p->scond, &p->from, p->reg, &p->to); - break; - - case AWORD: - fmtprint(fp, "(%d) WORD %D", p->line, &p->to); - break; - - case ADWORD: - fmtprint(fp, "(%d) DWORD %D %D", p->line, &p->from, &p->to); - break; - } - - if(p->spadj) - fmtprint(fp, " (spadj%+d)", p->spadj); - - return 0; -} - -int -Aconv(Fmt *fp) -{ - char *s; - int a; - - a = va_arg(fp->args, int); - s = "???"; - if(a >= AXXX && a < ALAST) - s = anames[a]; - return fmtstrcpy(fp, s); -} - -char* strcond[16] = -{ - ".EQ", - ".NE", - ".HS", - ".LO", - ".MI", - ".PL", - ".VS", - ".VC", - ".HI", - ".LS", - ".GE", - ".LT", - ".GT", - ".LE", - "", - ".NV" -}; - -int -Cconv(Fmt *fp) -{ - char s[20]; - int c; - - c = va_arg(fp->args, int); - strcpy(s, strcond[c & C_SCOND]); - if(c & C_SBIT) - strcat(s, ".S"); - if(c & C_PBIT) - strcat(s, ".P"); - if(c & C_WBIT) - strcat(s, ".W"); - if(c & C_UBIT) /* ambiguous with FBIT */ - strcat(s, ".U"); - return fmtstrcpy(fp, s); -} - -int -Dconv(Fmt *fp) -{ - char str[STRINGSZ]; - const char *op; - Adr *a; - int32 v; - - a = va_arg(fp->args, Adr*); - switch(a->type) { - - default: - 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) - snprint(str, sizeof str, "%N(R%d)(NONE)", a, a->reg); - break; - - case D_CONST: - if(a->reg == NREG) - snprint(str, sizeof str, "$%N", a); - else - snprint(str, sizeof str, "$%N(R%d)", a, a->reg); - break; - - case D_CONST2: - 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)) - snprint(str, sizeof str, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15); - else - snprint(str, sizeof str, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31); - if(a->reg != NREG) - seprint(str+strlen(str), str+sizeof str, "(R%d)", a->reg); - break; - - case D_OCONST: - snprint(str, sizeof str, "$*$%N", a); - if(a->reg != NREG) - snprint(str, sizeof str, "%N(R%d)(CONST)", a, a->reg); - break; - - case D_OREG: - if(a->reg != NREG) - snprint(str, sizeof str, "%N(R%d)", a, a->reg); - else - snprint(str, sizeof str, "%N", a); - break; - - case D_REG: - snprint(str, sizeof str, "R%d", a->reg); - if(a->name != D_NONE || a->sym != S) - snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg); - break; - - case D_REGREG: - snprint(str, sizeof str, "(R%d,R%d)", a->reg, (int)a->offset); - if(a->name != D_NONE || a->sym != S) - snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg); - break; - - case D_REGREG2: - snprint(str, sizeof str, "R%d,R%d", a->reg, (int)a->offset); - if(a->name != D_NONE || a->sym != S) - snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg); - break; - - case D_FREG: - snprint(str, sizeof str, "F%d", a->reg); - if(a->name != D_NONE || a->sym != S) - snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg); - break; - - case D_PSR: - switch(a->reg) { - case 0: - snprint(str, sizeof str, "CPSR"); - break; - case 1: - snprint(str, sizeof str, "SPSR"); - break; - default: - snprint(str, sizeof str, "PSR%d", a->reg); - break; - } - if(a->name != D_NONE || a->sym != S) - snprint(str, sizeof str, "%N(PSR%d)(REG)", a, a->reg); - break; - - case D_FPCR: - switch(a->reg){ - case 0: - snprint(str, sizeof str, "FPSR"); - break; - case 1: - snprint(str, sizeof str, "FPCR"); - break; - default: - snprint(str, sizeof str, "FCR%d", a->reg); - break; - } - if(a->name != D_NONE || a->sym != S) - snprint(str, sizeof str, "%N(FCR%d)(REG)", a, a->reg); - - break; - - case D_BRANCH: /* botch */ - if(curp->cond != P) { - v = curp->cond->pc; - if(a->sym != S) - snprint(str, sizeof str, "%s+%.5ux(BRANCH)", a->sym->name, v); - else - snprint(str, sizeof str, "%.5ux(BRANCH)", v); - } else - if(a->sym != S) - snprint(str, sizeof str, "%s+%d(APC)", a->sym->name, a->offset); - else - snprint(str, sizeof str, "%d(APC)", a->offset); - break; - - case D_FCONST: - snprint(str, sizeof str, "$%e", ieeedtod(&a->ieee)); - break; - - case D_SCONST: - snprint(str, sizeof str, "$\"%S\"", a->sval); - break; - } - return fmtstrcpy(fp, str); -} - -int -Nconv(Fmt *fp) -{ - char str[STRINGSZ]; - Adr *a; - Sym *s; - - a = va_arg(fp->args, Adr*); - s = a->sym; - switch(a->name) { - default: - sprint(str, "GOK-name(%d)", a->name); - break; - - case D_NONE: - sprint(str, "%d", a->offset); - break; - - case D_EXTERN: - if(s == S) - sprint(str, "%d(SB)", a->offset); - else - sprint(str, "%s+%d(SB)", s->name, a->offset); - break; - - case D_STATIC: - if(s == S) - sprint(str, "<>+%d(SB)", a->offset); - else - sprint(str, "%s<>+%d(SB)", s->name, a->offset); - break; - - case D_AUTO: - if(s == S) - sprint(str, "%d(SP)", a->offset); - else - sprint(str, "%s-%d(SP)", s->name, -a->offset); - break; - - case D_PARAM: - if(s == S) - sprint(str, "%d(FP)", a->offset); - else - sprint(str, "%s+%d(FP)", s->name, a->offset); - break; - } - return fmtstrcpy(fp, str); -} - -int -Sconv(Fmt *fp) -{ - int i, c; - char str[STRINGSZ], *p, *a; - - a = va_arg(fp->args, char*); - p = str; - for(i=0; i= 'a' && c <= 'z' || - c >= 'A' && c <= 'Z' || - c >= '0' && c <= '9' || - c == ' ' || c == '%') { - *p++ = c; - continue; - } - *p++ = '\\'; - switch(c) { - case 0: - *p++ = 'z'; - continue; - case '\\': - case '"': - *p++ = c; - continue; - case '\n': - *p++ = 'n'; - continue; - case '\t': - *p++ = 't'; - continue; - } - *p++ = (c>>6) + '0'; - *p++ = ((c>>3) & 7) + '0'; - *p++ = (c & 7) + '0'; - } - *p = 0; - return fmtstrcpy(fp, str); -} - int Iconv(Fmt *fp) { @@ -413,83 +68,3 @@ Iconv(Fmt *fp) free(s); return 0; } - -static char* -cnames[] = -{ - [C_ADDR] = "C_ADDR", - [C_FAUTO] = "C_FAUTO", - [C_ZFCON] = "C_SFCON", - [C_SFCON] = "C_SFCON", - [C_LFCON] = "C_LFCON", - [C_FCR] = "C_FCR", - [C_FOREG] = "C_FOREG", - [C_FREG] = "C_FREG", - [C_GOK] = "C_GOK", - [C_HAUTO] = "C_HAUTO", - [C_HFAUTO] = "C_HFAUTO", - [C_HFOREG] = "C_HFOREG", - [C_HOREG] = "C_HOREG", - [C_HREG] = "C_HREG", - [C_LACON] = "C_LACON", - [C_LAUTO] = "C_LAUTO", - [C_LBRA] = "C_LBRA", - [C_LCON] = "C_LCON", - [C_LCONADDR] = "C_LCONADDR", - [C_LOREG] = "C_LOREG", - [C_NCON] = "C_NCON", - [C_NONE] = "C_NONE", - [C_PC] = "C_PC", - [C_PSR] = "C_PSR", - [C_RACON] = "C_RACON", - [C_RCON] = "C_RCON", - [C_REG] = "C_REG", - [C_REGREG] = "C_REGREG", - [C_REGREG2] = "C_REGREG2", - [C_ROREG] = "C_ROREG", - [C_SAUTO] = "C_SAUTO", - [C_SBRA] = "C_SBRA", - [C_SCON] = "C_SCON", - [C_SHIFT] = "C_SHIFT", - [C_SOREG] = "C_SOREG", - [C_SP] = "C_SP", - [C_SROREG] = "C_SROREG" -}; - -int -Oconv(Fmt *fp) -{ - char buf[500]; - int o; - - o = va_arg(fp->args, int); - if(o < 0 || o >= nelem(cnames) || cnames[o] == nil) { - snprint(buf, sizeof(buf), "C_%d", o); - return fmtstrcpy(fp, buf); - } - return fmtstrcpy(fp, cnames[o]); -} - -void -diag(char *fmt, ...) -{ - char buf[1024], *tn, *sep; - va_list arg; - - 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%s\n", tn, sep, buf); - - nerrors++; - if(nerrors > 20) { - print("too many errors\n"); - errorexit(); - } -} diff --git a/src/cmd/5l/noop.c b/src/cmd/5l/noop.c index 305ed684e..d42c86289 100644 --- a/src/cmd/5l/noop.c +++ b/src/cmd/5l/noop.c @@ -32,677 +32,12 @@ #include "l.h" #include "../ld/lib.h" -#include "../../pkg/runtime/stack.h" - -static Sym* sym_div; -static Sym* sym_divu; -static Sym* sym_mod; -static Sym* sym_modu; -static Sym* symmorestack; -static Prog* pmorestack; - -static Prog* stacksplit(Prog*, int32); - -static void -linkcase(Prog *casep) -{ - Prog *p; - - for(p = casep; p != P; p = p->link){ - if(p->as == ABCASE) { - for(; p != P && p->as == ABCASE; p = p->link) - p->pcrel = casep; - break; - } - } -} void noops(void) { - Prog *p, *q, *q1, *q2; - int o; - Sym *tlsfallback, *gmsym; - - /* - * find leaf subroutines - * strip NOPs - * expand RET - * expand BECOME pseudo - * fixup TLS - */ - - if(debug['v']) - Bprint(&bso, "%5.2f noops\n", cputime()); - Bflush(&bso); - - symmorestack = lookup("runtime.morestack", 0); - if(symmorestack->type != STEXT) { - diag("runtime·morestack not defined"); - errorexit(); - } - pmorestack = symmorestack->text; - pmorestack->reg |= NOSPLIT; - - tlsfallback = lookup("runtime.read_tls_fallback", 0); - gmsym = S; - if(linkmode == LinkExternal) - gmsym = lookup("runtime.tlsgm", 0); - q = P; - for(cursym = textp; cursym != nil; cursym = cursym->next) { - for(p = cursym->text; p != P; p = p->link) { - switch(p->as) { - case ACASE: - if(flag_shared) - linkcase(p); - break; - - 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; - 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; - case AWORD: - // Rewrite TLS register fetch: MRC 15, 0, , C13, C0, 3 - if((p->to.offset & 0xffff0fff) == 0xee1d0f70) { - if(HEADTYPE == Hopenbsd) { - p->as = ARET; - } else if(goarm < 7) { - if(tlsfallback->type != STEXT) { - diag("runtime·read_tls_fallback not defined"); - errorexit(); - } - // BL runtime.read_tls_fallback(SB) - p->as = ABL; - p->to.type = D_BRANCH; - p->to.sym = tlsfallback; - p->cond = tlsfallback->text; - p->to.offset = 0; - cursym->text->mark &= ~LEAF; - } - if(linkmode == LinkExternal) { - // runtime.tlsgm is relocated with R_ARM_TLS_LE32 - // and $runtime.tlsgm will contain the TLS offset. - // - // MOV $runtime.tlsgm+tlsoffset(SB), REGTMP - // ADD REGTMP, - // - // In shared mode, runtime.tlsgm is relocated with - // R_ARM_TLS_IE32 and runtime.tlsgm(SB) will point - // to the GOT entry containing the TLS offset. - // - // MOV runtime.tlsgm(SB), REGTMP - // ADD REGTMP, - // SUB -tlsoffset, - // - // The SUB compensates for tlsoffset - // used in runtime.save_gm and runtime.load_gm. - q = p; - p = appendp(p); - p->as = AMOVW; - p->scond = 14; - p->reg = NREG; - if(flag_shared) { - p->from.type = D_OREG; - p->from.offset = 0; - } else { - p->from.type = D_CONST; - p->from.offset = tlsoffset; - } - p->from.sym = gmsym; - p->from.name = D_EXTERN; - p->to.type = D_REG; - p->to.reg = REGTMP; - p->to.offset = 0; - - p = appendp(p); - p->as = AADD; - p->scond = 14; - p->reg = NREG; - p->from.type = D_REG; - p->from.reg = REGTMP; - p->to.type = D_REG; - p->to.reg = (q->to.offset & 0xf000) >> 12; - p->to.offset = 0; - - if(flag_shared) { - p = appendp(p); - p->as = ASUB; - p->scond = 14; - p->reg = NREG; - p->from.type = D_CONST; - p->from.offset = -tlsoffset; - p->to.type = D_REG; - p->to.reg = (q->to.offset & 0xf000) >> 12; - p->to.offset = 0; - } - } - } - } - q = p; - } - } - - for(cursym = textp; cursym != nil; cursym = cursym->next) { - for(p = cursym->text; p != P; p = p->link) { - 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; - } - if(cursym->text->mark & LEAF) { - cursym->leaf = 1; - if(!autosize) - break; - } - - if(!(p->reg & NOSPLIT)) - p = stacksplit(p, autosize); // emit split check - - // 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; - p->spadj = autosize; - - if(cursym->text->reg & WRAPPER) { - // g->panicwrap += autosize; - // MOVW panicwrap_offset(g), R3 - // ADD $autosize, R3 - // MOVW R3 panicwrap_offset(g) - p = appendp(p); - p->as = AMOVW; - p->from.type = D_OREG; - p->from.reg = REGG; - p->from.offset = 2*PtrSize; - p->to.type = D_REG; - p->to.reg = 3; - - p = appendp(p); - p->as = AADD; - p->from.type = D_CONST; - p->from.offset = autosize; - p->to.type = D_REG; - p->to.reg = 3; - - p = appendp(p); - p->as = AMOVW; - p->from.type = D_REG; - p->from.reg = 3; - p->to.type = D_OREG; - p->to.reg = REGG; - p->to.offset = 2*PtrSize; - } - break; - - case ARET: - nocache(p); - if(cursym->text->mark & LEAF) { - if(!autosize) { - p->as = AB; - p->from = zprg.from; - if(p->to.sym) { // retjmp - p->to.type = D_BRANCH; - p->cond = p->to.sym->text; - } else { - p->to.type = D_OREG; - p->to.offset = 0; - p->to.reg = REGLINK; - } - break; - } - } - - if(cursym->text->reg & WRAPPER) { - int cond; - - // Preserve original RET's cond, to allow RET.EQ - // in the implementation of reflect.call. - cond = p->scond; - p->scond = C_SCOND_NONE; - - // g->panicwrap -= autosize; - // MOVW panicwrap_offset(g), R3 - // SUB $autosize, R3 - // MOVW R3 panicwrap_offset(g) - p->as = AMOVW; - p->from.type = D_OREG; - p->from.reg = REGG; - p->from.offset = 2*PtrSize; - p->to.type = D_REG; - p->to.reg = 3; - p = appendp(p); - - p->as = ASUB; - p->from.type = D_CONST; - p->from.offset = autosize; - p->to.type = D_REG; - p->to.reg = 3; - p = appendp(p); - - p->as = AMOVW; - p->from.type = D_REG; - p->from.reg = 3; - p->to.type = D_OREG; - p->to.reg = REGG; - p->to.offset = 2*PtrSize; - p = appendp(p); - - p->scond = cond; - } - - 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; - // If there are instructions following - // this ARET, they come from a branch - // with the same stackframe, so no spadj. - - if(p->to.sym) { // retjmp - p->to.reg = REGLINK; - q2 = appendp(p); - q2->as = AB; - q2->to.type = D_BRANCH; - q2->to.sym = p->to.sym; - q2->cond = p->to.sym->text; - p->to.sym = nil; - p = q2; - } - break; - - case AADD: - if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP) - p->spadj = -p->from.offset; - break; - - case ASUB: - if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP) - p->spadj = p->from.offset; - 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) */ - p = appendp(p); - 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 */ - p = appendp(p); - 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 = REGTMP; - p->to.offset = 0; - - /* CALL appropriate */ - p = appendp(p); - p->as = ABL; - 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; - } + LSym *s; - /* MOV REGTMP, b */ - p = appendp(p); - p->as = AMOVW; - p->line = q1->line; - p->from.type = D_REG; - p->from.reg = REGTMP; - p->from.offset = 0; - p->to.type = D_REG; - p->to.reg = q1->to.reg; - - /* ADD $8,SP */ - p = appendp(p); - p->as = AADD; - p->line = q1->line; - 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; - p->spadj = -8; - - /* Keep saved LR at 0(SP) after SP change. */ - /* MOVW 0(SP), REGTMP; MOVW REGTMP, -8!(SP) */ - /* TODO: Remove SP adjustments; see issue 6699. */ - q1->as = AMOVW; - q1->from.type = D_OREG; - q1->from.reg = REGSP; - q1->from.offset = 0; - q1->reg = NREG; - q1->to.type = D_REG; - q1->to.reg = REGTMP; - - /* SUB $8,SP */ - q1 = appendp(q1); - q1->as = AMOVW; - q1->from.type = D_REG; - q1->from.reg = REGTMP; - q1->reg = NREG; - q1->to.type = D_OREG; - q1->to.reg = REGSP; - q1->to.offset = -8; - q1->scond |= C_WBIT; - q1->spadj = 8; - - break; - case AMOVW: - if((p->scond & C_WBIT) && p->to.type == D_OREG && p->to.reg == REGSP) - p->spadj = -p->to.offset; - if((p->scond & C_PBIT) && p->from.type == D_OREG && p->from.reg == REGSP && p->to.reg != REGPC) - p->spadj = -p->from.offset; - if(p->from.type == D_CONST && p->from.reg == REGSP && p->to.type == D_REG && p->to.reg == REGSP) - p->spadj = -p->from.offset; - break; - } - } - } -} - -static Prog* -stacksplit(Prog *p, int32 framesize) -{ - int32 arg; - - // 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(framesize <= StackSmall) { - // small stack: SP < stackguard - // CMP stackguard, SP - p = appendp(p); - p->as = ACMP; - p->from.type = D_REG; - p->from.reg = 1; - p->reg = REGSP; - } else if(framesize <= StackBig) { - // large stack: SP-framesize < stackguard-StackSmall - // MOVW $-framesize(SP), R2 - // CMP stackguard, R2 - p = appendp(p); - p->as = AMOVW; - p->from.type = D_CONST; - p->from.reg = REGSP; - p->from.offset = -framesize; - 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; - } else { - // Such a large stack we need to protect against wraparound - // if SP is close to zero. - // SP-stackguard+StackGuard < framesize + (StackGuard-StackSmall) - // The +StackGuard on both sides is required to keep the left side positive: - // SP is allowed to be slightly below stackguard. See stack.h. - // CMP $StackPreempt, R1 - // MOVW.NE $StackGuard(SP), R2 - // SUB.NE R1, R2 - // MOVW.NE $(framesize+(StackGuard-StackSmall)), R3 - // CMP.NE R3, R2 - p = appendp(p); - p->as = ACMP; - p->from.type = D_CONST; - p->from.offset = (uint32)StackPreempt; - p->reg = 1; - - p = appendp(p); - p->as = AMOVW; - p->from.type = D_CONST; - p->from.reg = REGSP; - p->from.offset = StackGuard; - p->to.type = D_REG; - p->to.reg = 2; - p->scond = C_SCOND_NE; - - p = appendp(p); - p->as = ASUB; - p->from.type = D_REG; - p->from.reg = 1; - p->to.type = D_REG; - p->to.reg = 2; - p->scond = C_SCOND_NE; - - p = appendp(p); - p->as = AMOVW; - p->from.type = D_CONST; - p->from.offset = framesize + (StackGuard - StackSmall); - p->to.type = D_REG; - p->to.reg = 3; - p->scond = C_SCOND_NE; - - p = appendp(p); - p->as = ACMP; - p->from.type = D_REG; - p->from.reg = 3; - p->reg = 2; - p->scond = C_SCOND_NE; - } - - // MOVW.LS $framesize, R1 - p = appendp(p); - p->as = AMOVW; - p->scond = C_SCOND_LS; - p->from.type = D_CONST; - p->from.offset = framesize; - p->to.type = D_REG; - p->to.reg = 1; - - // MOVW.LS $args, R2 - p = appendp(p); - p->as = AMOVW; - p->scond = C_SCOND_LS; - p->from.type = D_CONST; - arg = cursym->text->to.offset2; - if(arg == 1) // special marker for known 0 - arg = 0; - if(arg&3) - diag("misaligned argument size in stack split"); - p->from.offset = arg; - p->to.type = D_REG; - p->to.reg = 2; - - // MOVW.LS R14, R3 - p = appendp(p); - p->as = AMOVW; - p->scond = C_SCOND_LS; - p->from.type = D_REG; - p->from.reg = REGLINK; - p->to.type = D_REG; - p->to.reg = 3; - - // BL.LS runtime.morestack(SB) // modifies LR, returns with LO still asserted - p = appendp(p); - p->as = ABL; - p->scond = C_SCOND_LS; - p->to.type = D_BRANCH; - p->to.sym = symmorestack; - p->cond = pmorestack; - - // BLS start - p = appendp(p); - p->as = ABLS; - p->to.type = D_BRANCH; - p->cond = cursym->text->link; - - return p; -} - -static void -sigdiv(char *n) -{ - Sym *s; - - s = lookup(n, 0); - if(s->type == STEXT) - if(s->sig == 0) - s->sig = SIGNINTERN; -} - -void -divsig(void) -{ - sigdiv("_div"); - sigdiv("_divu"); - sigdiv("_mod"); - sigdiv("_modu"); -} - -void -initdiv(void) -{ - Sym *s2, *s3, *s4, *s5; - - if(prog_div != P) - return; - sym_div = s2 = lookup("_div", 0); - sym_divu = s3 = lookup("_divu", 0); - sym_mod = s4 = lookup("_mod", 0); - sym_modu = s5 = lookup("_modu", 0); - 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 = cursym->text; - } - if(prog_divu == P) { - diag("undefined: %s", s3->name); - prog_divu = cursym->text; - } - if(prog_mod == P) { - diag("undefined: %s", s4->name); - prog_mod = cursym->text; - } - if(prog_modu == P) { - diag("undefined: %s", s5->name); - prog_modu = cursym->text; - } -} - -void -nocache(Prog *p) -{ - p->optab = 0; - p->from.class = 0; - p->to.class = 0; + for(s = ctxt->textp; s != nil; s = s->next) + ctxt->arch->addstacksplit(ctxt, s); } diff --git a/src/cmd/5l/obj.c b/src/cmd/5l/obj.c index 80f5787dc..86a0ece2e 100644 --- a/src/cmd/5l/obj.c +++ b/src/cmd/5l/obj.c @@ -30,120 +30,24 @@ // Reading object files. -#define EXTERN #include "l.h" #include "../ld/lib.h" #include "../ld/elf.h" #include "../ld/dwarf.h" #include -#ifndef DEFAULT -#define DEFAULT '9' -#endif - -char *noname = ""; -char *thestring = "arm"; - -Header headers[] = { - "noheader", Hnoheader, - "risc", Hrisc, - "plan9", Hplan9x32, - "ixp1200", Hixp1200, - "ipaq", Hipaq, - "linux", Hlinux, - "freebsd", Hfreebsd, - "netbsd", Hnetbsd, - 0, 0 -}; - -/* - * -Hrisc -T0x10005000 -R4 is aif for risc os - * -Hplan9 -T4128 -R4096 is plan9 format - * -Hixp1200 is IXP1200 (raw) - * -Hipaq -T0xC0008010 -R1024 is ipaq - * -Hlinux -Tx -Rx is linux elf - * -Hfreebsd is freebsd elf - * -Hnetbsd is netbsd elf - */ +char *thestring = "arm"; +LinkArch *thelinkarch = &linkarm; void -main(int argc, char *argv[]) +linkarchinit(void) { - char *p; - Sym *s; - - Binit(&bso, 1, OWRITE); - listinit(); - nerrors = 0; - outfile = "5.out"; - HEADTYPE = -1; - INITTEXT = -1; - INITDAT = -1; - INITRND = -1; - INITENTRY = 0; - linkmode = LinkAuto; - nuxiinit(); - - p = getgoarm(); - if(p != nil) - goarm = atoi(p); - else - goarm = 6; - if(goarm == 5) - debug['F'] = 1; - - flagcount("1", "use alternate profiling code", &debug['1']); - flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo); - flagstr("E", "sym: entry symbol", &INITENTRY); - flagint32("D", "addr: data address", &INITDAT); - flagcount("G", "debug pseudo-ops", &debug['G']); - flagfn1("I", "interp: set ELF interp", setinterp); - flagfn1("L", "dir: add dir to library path", Lflag); - flagfn1("H", "head: header type", setheadtype); - flagcount("K", "add stack underflow checks", &debug['K']); - flagcount("M", "disable software div/mod", &debug['M']); - flagcount("O", "print pc-line tables", &debug['O']); - flagcount("P", "debug code generation", &debug['P']); - flagint32("R", "rnd: address rounding", &INITRND); - flagint32("T", "addr: text address", &INITTEXT); - flagfn0("V", "print version and exit", doversion); - flagcount("W", "disassemble input", &debug['W']); - flagfn2("X", "name value: define string data", addstrdata); - flagcount("Z", "clear stack frame on entry", &debug['Z']); - flagcount("a", "disassemble output", &debug['a']); - flagcount("c", "dump call graph", &debug['c']); - flagcount("d", "disable dynamic executable", &debug['d']); - flagstr("extld", "linker to run in external mode", &extld); - flagstr("extldflags", "flags for external linker", &extldflags); - flagcount("f", "ignore version mismatch", &debug['f']); - flagcount("g", "disable go package data checks", &debug['g']); - flagstr("installsuffix", "pkg directory suffix", &flag_installsuffix); - flagstr("k", "sym: set field tracking symbol", &tracksym); - flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode); - flagcount("n", "dump symbol table", &debug['n']); - flagstr("o", "outfile: set output file", &outfile); - flagcount("p", "insert profiling code", &debug['p']); - flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath); - flagcount("race", "enable race detector", &flag_race); - flagcount("s", "disable symbol table", &debug['s']); - flagcount("shared", "generate shared object (implies -linkmode external)", &flag_shared); - flagstr("tmpdir", "leave temporary files in this directory", &tmpdir); - flagcount("u", "reject unsafe packages", &debug['u']); - flagcount("v", "print link trace", &debug['v']); - flagcount("w", "disable DWARF generation", &debug['w']); - - flagparse(&argc, &argv, usage); - - if(argc != 1) - usage(); - - if(flag_shared) - linkmode = LinkExternal; - - mywhatsys(); +} - if(HEADTYPE == -1) - HEADTYPE = headtype(goos); +void +archinit(void) +{ + LSym *s; // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when // Go was built; see ../../make.bash. @@ -158,34 +62,15 @@ main(int argc, char *argv[]) sysfatal("cannot use -linkmode=external with -H %s", headstr(HEADTYPE)); break; case Hlinux: + case Hfreebsd: break; } - libinit(); - switch(HEADTYPE) { default: diag("unknown -H option"); errorexit(); - case Hnoheader: /* no header */ - HEADR = 0L; - if(INITTEXT == -1) - INITTEXT = 0; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = 4; - break; - case Hrisc: /* aif for risc os */ - HEADR = 128L; - if(INITTEXT == -1) - INITTEXT = 0x10005000 + HEADR; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = 4; - break; - case Hplan9x32: /* plan 9 */ + case Hplan9: /* plan 9 */ HEADR = 32L; if(INITTEXT == -1) INITTEXT = 4128; @@ -194,30 +79,11 @@ main(int argc, char *argv[]) if(INITRND == -1) INITRND = 4096; break; - case Hixp1200: /* boot for IXP1200 */ - HEADR = 0L; - if(INITTEXT == -1) - INITTEXT = 0x0; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = 4; - break; - case Hipaq: /* boot for ipaq */ - HEADR = 16L; - if(INITTEXT == -1) - INITTEXT = 0xC0008010; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = 1024; - break; case Hlinux: /* arm elf */ case Hfreebsd: case Hnetbsd: + case Hnacl: debug['d'] = 0; // with dynamic linking - tlsoffset = -8; // hardcoded number, first 4-byte word for g, and then 4-byte word for m - // this number is known to ../../pkg/runtime/rt0_*_arm.s elfinit(); HEADR = ELFRESERVE; if(INITTEXT == -1) @@ -231,578 +97,9 @@ main(int argc, char *argv[]) if(INITDAT != 0 && INITRND != 0) print("warning: -D0x%ux is ignored because of -R0x%ux\n", INITDAT, INITRND); - if(debug['v']) - Bprint(&bso, "HEADER = -H0x%d -T0x%ux -D0x%ux -R0x%ux\n", - HEADTYPE, INITTEXT, INITDAT, INITRND); - Bflush(&bso); - zprg.as = AGOK; - zprg.scond = 14; - zprg.reg = NREG; - zprg.from.name = D_NONE; - zprg.from.type = D_NONE; - zprg.from.reg = NREG; - zprg.to = zprg.from; - buildop(); - histgen = 0; - pc = 0; - dtype = 4; - - version = 0; - cbp = buf.cbuf; - cbc = sizeof(buf.cbuf); // embed goarm to runtime.goarm - s = lookup("runtime.goarm", 0); - s->dupok = 1; - adduint8(s, goarm); - - addlibpath("command line", "command line", argv[0], "main"); - loadlib(); - - // mark some functions that are only referenced after linker code editing - if(debug['F']) - mark(rlookup("_sfloat", 0)); - mark(lookup("runtime.read_tls_fallback", 0)); - deadcode(); - if(textp == nil) { - diag("no code"); - errorexit(); - } - - patch(); - if(debug['p']) - if(debug['1']) - doprof1(); - else - doprof2(); - doelf(); - follow(); - softfloat(); - // 5l -Z means zero the stack frame on entry. - // This slows down function calls but can help avoid - // false positives in garbage collection. - if(debug['Z']) - dozerostk(); - noops(); // generate stack split prolog, handle div/mod, etc. - dostkcheck(); - span(); - addexport(); - // textaddress() functionality is handled in span() - pclntab(); - symtab(); - dodata(); - address(); - doweak(); - reloc(); - asmb(); - undef(); - hostlink(); - - if(debug['c']) - print("ARM size = %d\n", armsize); - if(debug['v']) { - Bprint(&bso, "%5.2f cpu time\n", cputime()); - Bprint(&bso, "%d sizeof adr\n", sizeof(Adr)); - Bprint(&bso, "%d sizeof prog\n", sizeof(Prog)); - } - Bflush(&bso); - errorexit(); -} - -static Sym* -zsym(char *pn, Biobuf *f, Sym *h[]) -{ - int o; - - o = BGETC(f); - if(o == 0) - return S; - 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 i, c; - int32 l; - Sym *s; - Auto *u; - - a->type = BGETC(f); - a->reg = BGETC(f); - c = BGETC(f); - if(c < 0 || c > NSYM){ - print("sym out of range: %d\n", c); - BPUTC(f, ALAST+1); - return; - } - a->sym = h[c]; - a->name = BGETC(f); - adrgotype = zsym(pn, f, h); - - if((schar)a->reg < 0 || a->reg > NREG) { - print("register out of range %d\n", a->reg); - BPUTC(f, ALAST+1); - return; /* force real diagnostic */ - } - - 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 == 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 - } - } - } - - switch(a->type) { - default: - print("unknown type %d\n", a->type); - BPUTC(f, ALAST+1); - return; /* force real diagnostic */ - - case D_NONE: - case D_REG: - case D_FREG: - case D_PSR: - case D_FPCR: - break; - - case D_REGREG: - case D_REGREG2: - a->offset = BGETC(f); - break; - - case D_CONST2: - a->offset2 = BGETLE4(f); // fall through - case D_BRANCH: - case D_OREG: - case D_CONST: - case D_OCONST: - case D_SHIFT: - a->offset = BGETLE4(f); - break; - - case D_SCONST: - a->sval = mal(NSNAME); - Bread(f, a->sval, NSNAME); - break; - - case D_FCONST: - a->ieee.l = BGETLE4(f); - a->ieee.h = BGETLE4(f); - break; - } - s = a->sym; - if(s == S) - return; - i = a->name; - if(i != D_AUTO && i != D_PARAM) { - if(s && adrgotype) - s->gotype = adrgotype; - return; - } - - l = a->offset; - for(u=curauto; u; u=u->link) - if(u->asym == s) - if(u->type == i) { - if(u->aoffset > l) - u->aoffset = l; - if(adrgotype) - u->gotype = adrgotype; - return; - } - - u = mal(sizeof(Auto)); - u->link = curauto; - curauto = u; - u->asym = s; - u->aoffset = l; - u->type = i; - u->gotype = adrgotype; -} - -void -nopout(Prog *p) -{ - p->as = ANOP; - p->from.type = D_NONE; - p->to.type = D_NONE; -} - -void -ldobj1(Biobuf *f, char *pkg, int64 len, char *pn) -{ - int32 ipc; - Prog *p; - Sym *h[NSYM], *s; - int v, o, r, skip; - uint32 sig; - char *name; - int ntext; - int32 eof; - char src[1024], *x; - Prog *lastp; - - lastp = nil; - ntext = 0; - eof = Boffset(f) + len; - src[0] = 0; - pn = estrdup(pn); // we keep it in Sym* references - -newloop: - memset(h, 0, sizeof(h)); - version++; - histfrogp = 0; - ipc = pc; - skip = 0; - -loop: - if(f->state == Bracteof || Boffset(f) >= eof) - goto eof; - o = BGETC(f); - if(o == Beof) - goto eof; - - if(o <= AXXX || o >= ALAST) { - diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o); - print(" probably not a .5 file\n"); - errorexit(); - } - if(o == ANAME || o == ASIGNAME) { - sig = 0; - if(o == ASIGNAME) - sig = BGETLE4(f); - v = BGETC(f); /* type */ - o = BGETC(f); /* sym */ - r = 0; - if(v == D_STATIC) - r = version; - name = Brdline(f, '\0'); - if(name == nil) { - if(Blinelen(f) > 0) { - fprint(2, "%s: name too long\n", pn); - errorexit(); - } - goto eof; - } - x = expandpkg(name, pkg); - s = lookup(x, r); - if(x != name) - free(x); - - if(sig != 0){ - if(s->sig != 0 && s->sig != sig) - 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; - if(v == D_FILE) { - if(s->type != SFILE) { - histgen++; - s->type = SFILE; - s->value = histgen; - } - if(histfrogp < MAXHIST) { - histfrog[histfrogp] = s; - histfrogp++; - } else - collapsefrog(s); - dwarfaddfrag(s->value, s->name); - } - goto loop; - } - - p = mal(sizeof(Prog)); - p->as = o; - p->scond = BGETC(f); - p->reg = BGETC(f); - p->line = BGETLE4(f); - - zaddr(pn, f, &p->from, h); - fromgotype = adrgotype; - zaddr(pn, f, &p->to, h); - - 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; - - if(debug['W']) - print("%P\n", p); - - switch(o) { - case AHISTORY: - if(p->to.offset == -1) { - addlib(src, pn); - histfrogp = 0; - goto loop; - } - if(src[0] == '\0') - copyhistfrog(src, sizeof src); - addhist(p->line, D_FILE); /* 'z' */ - if(p->to.offset) - addhist(p->to.offset, D_FILE1); /* 'Z' */ - savehist(p->line, p->to.offset); - histfrogp = 0; - goto loop; - - case AEND: - histtoauto(); - if(cursym != nil && cursym->text) - cursym->autom = curauto; - curauto = 0; - cursym = nil; - if(Boffset(f) == eof) - return; - goto newloop; - - case AGLOBL: - s = p->from.sym; - if(s == S) { - diag("GLOBL must have a name\n%P", p); - errorexit(); - } - if(s->type == 0 || s->type == SXREF) { - s->type = SBSS; - s->value = 0; - } - if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) { - diag("redefinition: %s\n%P", s->name, p); - s->type = SBSS; - s->value = 0; - } - if(p->to.offset > s->size) - s->size = p->to.offset; - if(p->reg & DUPOK) - s->dupok = 1; - if(p->reg & RODATA) - s->type = SRODATA; - else if(p->reg & NOPTR) - s->type = SNOPTRBSS; - 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->dupok) { -// if(debug['v']) -// Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn); - goto loop; - } - 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(); - } - savedata(s, p, pn); - unmal(p, sizeof *p); - break; - - case AGOK: - diag("unknown opcode\n%P", p); - p->pc = pc; - pc++; - break; - - case ATYPE: - if(skip) - goto casedef; - pc++; - goto loop; - - case ATEXT: - if(cursym != nil && cursym->text) { - histtoauto(); - cursym->autom = curauto; - curauto = 0; - } - s = p->from.sym; - if(s == S) { - diag("TEXT must have a name\n%P", p); - errorexit(); - } - cursym = s; - if(s->type != 0 && s->type != SXREF && (p->reg & DUPOK)) { - skip = 1; - goto casedef; - } - 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) - diag("redefinition: %s\n%P", s->name, p); - if(etextp) - etextp->next = s; - else - textp = s; - if(fromgotype) { - if(s->gotype && s->gotype != fromgotype) - diag("%s: type mismatch for %s", pn, s->name); - s->gotype = fromgotype; - } - etextp = s; - p->align = 4; - autosize = (p->to.offset+3L) & ~3L; - p->to.offset = autosize; - autosize += 4; - s->type = STEXT; - s->hist = gethist(); - s->text = p; - s->value = pc; - s->args = p->to.offset2; - lastp = p; - p->pc = pc; - pc++; - break; - - case ASUB: - if(p->from.type == D_CONST) - if(p->from.name == D_NONE) - if(p->from.offset < 0) { - p->from.offset = -p->from.offset; - p->as = AADD; - } - goto casedef; - - case AADD: - if(p->from.type == D_CONST) - if(p->from.name == D_NONE) - if(p->from.offset < 0) { - p->from.offset = -p->from.offset; - p->as = ASUB; - } - goto casedef; - - 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 casedef; - - case AMOVF: - if(skip) - goto casedef; - - 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, "$%ux", ieeedtof(&p->from.ieee)); - s = lookup(literal, 0); - if(s->type == 0) { - s->type = SRODATA; - adduint32(s, ieeedtof(&p->from.ieee)); - s->reachable = 0; - } - p->from.type = D_OREG; - p->from.sym = s; - p->from.name = D_EXTERN; - p->from.offset = 0; - } - goto casedef; - - case AMOVD: - if(skip) - goto casedef; - - 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, "$%ux.%ux", - p->from.ieee.l, p->from.ieee.h); - s = lookup(literal, 0); - if(s->type == 0) { - s->type = SRODATA; - adduint32(s, p->from.ieee.l); - adduint32(s, p->from.ieee.h); - s->reachable = 0; - } - p->from.type = D_OREG; - p->from.sym = s; - p->from.name = D_EXTERN; - p->from.offset = 0; - } - goto casedef; - - default: - 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; - break; - } - goto loop; - -eof: - diag("truncated object file: %s", pn); -} - -Prog* -prg(void) -{ - Prog *p; - - p = mal(sizeof(Prog)); - *p = zprg; - return p; -} - -Prog* -appendp(Prog *q) -{ - Prog *p; - - p = prg(); - p->link = q->link; - q->link = p; - p->line = q->line; - return p; + s = linklookup(ctxt, "runtime.goarm", 0); + s->type = SRODATA; + adduint8(ctxt, s, ctxt->goarm); } diff --git a/src/cmd/5l/optab.c b/src/cmd/5l/optab.c deleted file mode 100644 index 3d05d6d09..000000000 --- a/src/cmd/5l/optab.c +++ /dev/null @@ -1,277 +0,0 @@ -// Inferno utils/5l/optab.c -// http://code.google.com/p/inferno-os/source/browse/utils/5l/optab.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 "l.h" - -Optab optab[] = -{ - /* struct Optab: - OPCODE, from, prog->reg, to, type,size,param,flag */ - { ATEXT, C_ADDR, C_NONE, C_LCON, 0, 0, 0 }, - { ATEXT, C_ADDR, C_REG, C_LCON, 0, 0, 0 }, - - { AADD, C_REG, C_REG, C_REG, 1, 4, 0 }, - { AADD, C_REG, C_NONE, C_REG, 1, 4, 0 }, - { AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0 }, - { AMVN, C_REG, C_NONE, C_REG, 1, 4, 0 }, - { ACMP, C_REG, C_REG, C_NONE, 1, 4, 0 }, - - { AADD, C_RCON, C_REG, C_REG, 2, 4, 0 }, - { AADD, C_RCON, C_NONE, C_REG, 2, 4, 0 }, - { AMOVW, C_RCON, C_NONE, C_REG, 2, 4, 0 }, - { AMVN, C_RCON, C_NONE, C_REG, 2, 4, 0 }, - { ACMP, C_RCON, C_REG, C_NONE, 2, 4, 0 }, - - { AADD, C_SHIFT,C_REG, C_REG, 3, 4, 0 }, - { AADD, C_SHIFT,C_NONE, C_REG, 3, 4, 0 }, - { AMVN, C_SHIFT,C_NONE, C_REG, 3, 4, 0 }, - { ACMP, C_SHIFT,C_REG, C_NONE, 3, 4, 0 }, - - { AMOVW, C_RACON,C_NONE, C_REG, 4, 4, REGSP }, - - { AB, C_NONE, C_NONE, C_SBRA, 5, 4, 0, LPOOL }, - { ABL, C_NONE, C_NONE, C_SBRA, 5, 4, 0 }, - { ABX, C_NONE, C_NONE, C_SBRA, 74, 20, 0 }, - { ABEQ, C_NONE, C_NONE, C_SBRA, 5, 4, 0 }, - - { AB, C_NONE, C_NONE, C_ROREG, 6, 4, 0, LPOOL }, - { ABL, C_NONE, C_NONE, C_ROREG, 7, 4, 0 }, - { ABL, C_REG, C_NONE, C_ROREG, 7, 4, 0 }, - { ABX, C_NONE, C_NONE, C_ROREG, 75, 12, 0 }, - { ABXRET, C_NONE, C_NONE, C_ROREG, 76, 4, 0 }, - - { ASLL, C_RCON, C_REG, C_REG, 8, 4, 0 }, - { ASLL, C_RCON, C_NONE, C_REG, 8, 4, 0 }, - - { ASLL, C_REG, C_NONE, C_REG, 9, 4, 0 }, - { ASLL, C_REG, C_REG, C_REG, 9, 4, 0 }, - - { ASWI, C_NONE, C_NONE, C_NONE, 10, 4, 0 }, - { ASWI, C_NONE, C_NONE, C_LOREG, 10, 4, 0 }, - { ASWI, C_NONE, C_NONE, C_LCON, 10, 4, 0 }, - - { AWORD, C_NONE, C_NONE, C_LCON, 11, 4, 0 }, - { AWORD, C_NONE, C_NONE, C_LCONADDR, 11, 4, 0 }, - { AWORD, C_NONE, C_NONE, C_ADDR, 11, 4, 0 }, - - { AMOVW, C_NCON, C_NONE, C_REG, 12, 4, 0 }, - { AMOVW, C_LCON, C_NONE, C_REG, 12, 4, 0, LFROM }, - { AMOVW, C_LCONADDR, C_NONE, C_REG, 12, 4, 0, LFROM | LPCREL, 4}, - - { AADD, C_NCON, C_REG, C_REG, 13, 8, 0 }, - { AADD, C_NCON, C_NONE, C_REG, 13, 8, 0 }, - { AMVN, C_NCON, C_NONE, C_REG, 13, 8, 0 }, - { ACMP, C_NCON, C_REG, C_NONE, 13, 8, 0 }, - { AADD, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM }, - { AADD, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM }, - { AMVN, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM }, - { ACMP, C_LCON, C_REG, C_NONE, 13, 8, 0, LFROM }, - - { AMOVB, C_REG, C_NONE, C_REG, 1, 4, 0 }, - { AMOVBS, C_REG, C_NONE, C_REG, 14, 8, 0 }, - { AMOVBU, C_REG, C_NONE, C_REG, 58, 4, 0 }, - { AMOVH, C_REG, C_NONE, C_REG, 1, 4, 0 }, - { AMOVHS, C_REG, C_NONE, C_REG, 14, 8, 0 }, - { AMOVHU, C_REG, C_NONE, C_REG, 14, 8, 0 }, - - { AMUL, C_REG, C_REG, C_REG, 15, 4, 0 }, - { AMUL, C_REG, C_NONE, C_REG, 15, 4, 0 }, - - { ADIV, C_REG, C_REG, C_REG, 16, 4, 0 }, - { ADIV, C_REG, C_NONE, C_REG, 16, 4, 0 }, - - { AMULL, C_REG, C_REG, C_REGREG, 17, 4, 0 }, - { AMULA, C_REG, C_REG, C_REGREG2, 17, 4, 0 }, - - { 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_SAUTO, 20, 4, REGSP }, - { AMOVB, C_REG, C_NONE, C_SOREG, 20, 4, 0 }, - { AMOVBS, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP }, - { AMOVBS, C_REG, C_NONE, C_SOREG, 20, 4, 0 }, - { AMOVBU, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP }, - { AMOVBU, C_REG, C_NONE, C_SOREG, 20, 4, 0 }, - - { AMOVW, C_SAUTO,C_NONE, C_REG, 21, 4, REGSP }, - { AMOVW, C_SOREG,C_NONE, C_REG, 21, 4, 0 }, - { AMOVBU, C_SAUTO,C_NONE, C_REG, 21, 4, REGSP }, - { AMOVBU, C_SOREG,C_NONE, C_REG, 21, 4, 0 }, - - { 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 | LPCREL, 4 }, - { 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 | LPCREL, 4 }, - { AMOVBS, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO }, - { AMOVBS, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO }, - { AMOVBS, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 }, - { 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 | LPCREL, 4 }, - - { 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 | LPCREL, 4 }, - { 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 | LPCREL, 4 }, - - { AMOVW, C_LACON,C_NONE, C_REG, 34, 8, REGSP, LFROM }, - - { AMOVW, C_PSR, C_NONE, C_REG, 35, 4, 0 }, - { AMOVW, C_REG, C_NONE, C_PSR, 36, 4, 0 }, - { AMOVW, C_RCON, C_NONE, C_PSR, 37, 4, 0 }, - - { AMOVM, C_LCON, C_NONE, C_SOREG, 38, 4, 0 }, - { AMOVM, C_SOREG,C_NONE, C_LCON, 39, 4, 0 }, - - { ASWPW, C_SOREG,C_REG, C_REG, 40, 4, 0 }, - - { ARFE, C_NONE, C_NONE, C_NONE, 41, 4, 0 }, - - { AMOVF, C_FREG, C_NONE, C_FAUTO, 50, 4, REGSP }, - { AMOVF, C_FREG, C_NONE, C_FOREG, 50, 4, 0 }, - - { 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_LAUTO, 52, 12, REGSP, LTO }, - { AMOVF, C_FREG, C_NONE, C_LOREG, 52, 12, 0, LTO }, - - { AMOVF, C_LAUTO,C_NONE, C_FREG, 53, 12, REGSP, LFROM }, - { AMOVF, C_LOREG,C_NONE, C_FREG, 53, 12, 0, LFROM }, - - { AMOVF, C_FREG, C_NONE, C_ADDR, 68, 8, 0, LTO | LPCREL, 4 }, - { AMOVF, C_ADDR, C_NONE, C_FREG, 69, 8, 0, LFROM | LPCREL, 4}, - - { AADDF, C_FREG, C_NONE, C_FREG, 54, 4, 0 }, - { AADDF, C_FREG, C_REG, C_FREG, 54, 4, 0 }, - { AMOVF, C_FREG, C_NONE, C_FREG, 54, 4, 0 }, - - { AMOVW, C_REG, C_NONE, C_FCR, 56, 4, 0 }, - { AMOVW, C_FCR, C_NONE, C_REG, 57, 4, 0 }, - - { AMOVW, C_SHIFT,C_NONE, C_REG, 59, 4, 0 }, - { AMOVBU, C_SHIFT,C_NONE, C_REG, 59, 4, 0 }, - - { AMOVB, C_SHIFT,C_NONE, C_REG, 60, 4, 0 }, - { AMOVBS, C_SHIFT,C_NONE, C_REG, 60, 4, 0 }, - - { AMOVW, C_REG, C_NONE, C_SHIFT, 61, 4, 0 }, - { AMOVB, C_REG, C_NONE, C_SHIFT, 61, 4, 0 }, - { AMOVBS, C_REG, C_NONE, C_SHIFT, 61, 4, 0 }, - { AMOVBU, C_REG, C_NONE, C_SHIFT, 61, 4, 0 }, - - { ACASE, C_REG, C_NONE, C_NONE, 62, 4, 0, LPCREL, 8 }, - { ABCASE, C_NONE, C_NONE, C_SBRA, 63, 4, 0, LPCREL, 0 }, - - { AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 }, - { AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 }, - { AMOVHS, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 }, - { AMOVHS, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 }, - { AMOVHU, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 }, - { AMOVHU, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 }, - - { AMOVB, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 }, - { AMOVB, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 }, - { AMOVBS, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 }, - { AMOVBS, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 }, - { AMOVH, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 }, - { AMOVH, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 }, - { AMOVHS, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 }, - { AMOVHS, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 }, - { AMOVHU, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 }, - { AMOVHU, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 }, - - { AMOVH, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO }, - { AMOVH, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO }, - { AMOVH, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4 }, - { AMOVHS, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO }, - { AMOVHS, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO }, - { AMOVHS, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4 }, - { AMOVHU, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO }, - { AMOVHU, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO }, - { AMOVHU, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4 }, - - { AMOVB, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM }, - { AMOVB, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM }, - { AMOVB, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 }, - { AMOVBS, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM }, - { AMOVBS, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM }, - { AMOVBS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 }, - { AMOVH, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM }, - { AMOVH, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM }, - { AMOVH, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 }, - { AMOVHS, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM }, - { AMOVHS, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM }, - { AMOVHS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 }, - { AMOVHU, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM }, - { AMOVHU, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM }, - { AMOVHU, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 }, - - { 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, 8, 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 }, - - { ATST, C_REG, C_NONE, C_NONE, 90, 4, 0 }, - - { ALDREXD, C_SOREG,C_NONE, C_REG, 91, 4, 0 }, - { ASTREXD, C_SOREG,C_REG, C_REG, 92, 4, 0 }, - - { APLD, C_SOREG,C_NONE, C_NONE, 95, 4, 0 }, - - { AUNDEF, C_NONE, C_NONE, C_NONE, 96, 4, 0 }, - - { ACLZ, C_REG, C_NONE, C_REG, 97, 4, 0 }, - - { AMULWT, C_REG, C_REG, C_REG, 98, 4, 0 }, - { AMULAWT, C_REG, C_REG, C_REGREG2, 99, 4, 0 }, - - { AUSEFIELD, C_ADDR, C_NONE, C_NONE, 0, 0, 0 }, - { APCDATA, C_LCON, C_NONE, C_LCON, 0, 0, 0 }, - { AFUNCDATA, C_LCON, C_NONE, C_ADDR, 0, 0, 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 deleted file mode 100644 index cd8897989..000000000 --- a/src/cmd/5l/pass.c +++ /dev/null @@ -1,409 +0,0 @@ -// Inferno utils/5l/pass.c -// http://code.google.com/p/inferno-os/source/browse/utils/5l/pass.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. - -// Code and data passes. - -#include "l.h" -#include "../ld/lib.h" - -static void xfol(Prog*, Prog**); - -Prog* -brchain(Prog *p) -{ - int i; - - for(i=0; i<20; i++) { - if(p == P || p->as != AB) - return p; - p = p->cond; - } - return P; -} - -int -relinv(int a) -{ - switch(a) { - case ABEQ: return ABNE; - case ABNE: return ABEQ; - case ABCS: return ABCC; - case ABHS: return ABLO; - case ABCC: return ABCS; - case ABLO: return ABHS; - case ABMI: return ABPL; - case ABPL: return ABMI; - case ABVS: return ABVC; - case ABVC: return ABVS; - case ABHI: return ABLS; - case ABLS: return ABHI; - case ABGE: return ABLT; - case ABLT: return ABGE; - case ABGT: return ABLE; - case ABLE: return ABGT; - } - diag("unknown relation: %s", anames[a]); - return a; -} - -void -follow(void) -{ - Prog *firstp, *lastp; - - if(debug['v']) - Bprint(&bso, "%5.2f follow\n", cputime()); - Bflush(&bso); - - for(cursym = textp; cursym != nil; cursym = cursym->next) { - firstp = prg(); - lastp = firstp; - xfol(cursym->text, &lastp); - lastp->link = nil; - cursym->text = firstp->link; - } -} - -static void -xfol(Prog *p, Prog **last) -{ - Prog *q, *r; - int a, i; - -loop: - if(p == P) - return; - a = p->as; - if(a == AB) { - q = p->cond; - if(q != P && q->as != ATEXT) { - p->mark |= FOLL; - p = q; - if(!(p->mark & FOLL)) - goto loop; - } - } - if(p->mark & FOLL) { - for(i=0,q=p; i<4; i++,q=q->link) { - if(q == *last || q == nil) - break; - a = q->as; - if(a == ANOP) { - i--; - continue; - } - if(a == AB || (a == ARET && q->scond == 14) || a == ARFE || a == AUNDEF) - goto copy; - if(q->cond == P || (q->cond->mark&FOLL)) - continue; - if(a != ABEQ && a != ABNE) - continue; - copy: - for(;;) { - r = prg(); - *r = *p; - if(!(r->mark&FOLL)) - print("can't happen 1\n"); - r->mark |= FOLL; - if(p != q) { - p = p->link; - (*last)->link = r; - *last = r; - continue; - } - (*last)->link = r; - *last = r; - if(a == AB || (a == ARET && q->scond == 14) || a == ARFE || a == AUNDEF) - return; - r->as = ABNE; - if(a == ABNE) - r->as = ABEQ; - r->cond = p->link; - r->link = p->cond; - if(!(r->link->mark&FOLL)) - xfol(r->link, last); - if(!(r->cond->mark&FOLL)) - print("can't happen 2\n"); - return; - } - } - a = AB; - q = prg(); - q->as = a; - q->line = p->line; - q->to.type = D_BRANCH; - q->to.offset = p->pc; - q->cond = p; - p = q; - } - p->mark |= FOLL; - (*last)->link = p; - *last = p; - if(a == AB || (a == ARET && p->scond == 14) || a == ARFE || a == AUNDEF){ - return; - } - if(p->cond != P) - if(a != ABL && a != ABX && p->link != P) { - q = brchain(p->link); - if(a != ATEXT && a != ABCASE) - if(q != P && (q->mark&FOLL)) { - p->as = relinv(a); - p->link = p->cond; - p->cond = q; - } - xfol(p->link, last); - q = brchain(p->cond); - if(q == P) - q = p->cond; - if(q->mark&FOLL) { - p->cond = q; - return; - } - p = q; - goto loop; - } - p = p->link; - goto loop; -} - -void -patch(void) -{ - int32 c, vexit; - Prog *p, *q; - Sym *s; - int a; - - if(debug['v']) - Bprint(&bso, "%5.2f patch\n", cputime()); - Bflush(&bso); - mkfwd(); - s = lookup("exit", 0); - vexit = s->value; - for(cursym = textp; cursym != nil; cursym = cursym->next) { - for(p = cursym->text; p != P; p = p->link) { - a = p->as; - if((a == ABL || a == ABX || a == AB || a == ARET) && - p->to.type != D_BRANCH && p->to.sym != S) { - s = p->to.sym; - if(s->text == nil) - continue; - switch(s->type&SMASK) { - 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; - p->cond = 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(q == P) { - diag("branch out of range %d\n%P", c, p); - p->to.type = D_NONE; - } - p->cond = q; - } - } - if(flag_shared) { - s = lookup("init_array", 0); - s->type = SINITARR; - s->reachable = 1; - s->hide = 1; - addaddr(s, lookup(INITENTRY, 0)); - } - - for(cursym = textp; cursym != nil; cursym = cursym->next) { - for(p = cursym->text; p != P; p = p->link) { - 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; - } - } - } -} - -Prog* -brloop(Prog *p) -{ - Prog *q; - int c; - - for(c=0; p!=P;) { - if(p->as != AB) - return p; - q = p->cond; - if(q <= p) { - c++; - if(q == p || c > 5000) - break; - } - p = q; - } - return P; -} - -int32 -atolwhex(char *s) -{ - int32 n; - int f; - - n = 0; - f = 0; - while(*s == ' ' || *s == '\t') - s++; - if(*s == '-' || *s == '+') { - if(*s++ == '-') - f = 1; - while(*s == ' ' || *s == '\t') - s++; - } - if(s[0]=='0' && s[1]){ - if(s[1]=='x' || s[1]=='X'){ - s += 2; - for(;;){ - if(*s >= '0' && *s <= '9') - n = n*16 + *s++ - '0'; - else if(*s >= 'a' && *s <= 'f') - n = n*16 + *s++ - 'a' + 10; - else if(*s >= 'A' && *s <= 'F') - n = n*16 + *s++ - 'A' + 10; - else - break; - } - } else - while(*s >= '0' && *s <= '7') - n = n*8 + *s++ - '0'; - } else - while(*s >= '0' && *s <= '9') - n = n*10 + *s++ - '0'; - if(f) - n = -n; - return n; -} - -int32 -rnd(int32 v, int32 r) -{ - int32 c; - - if(r <= 0) - return v; - v += r - 1; - c = v % r; - if(c < 0) - c += r; - v -= c; - return v; -} - -void -dozerostk(void) -{ - Prog *p, *pl; - int32 autoffset; - - for(cursym = textp; cursym != nil; cursym = cursym->next) { - if(cursym->text == nil || cursym->text->link == nil) - continue; - p = cursym->text; - autoffset = p->to.offset; - if(autoffset < 0) - autoffset = 0; - if(autoffset && !(p->reg&NOSPLIT)) { - // MOVW $4(R13), R1 - p = appendp(p); - p->as = AMOVW; - p->from.type = D_CONST; - p->from.reg = 13; - p->from.offset = 4; - p->to.type = D_REG; - p->to.reg = 1; - - // MOVW $n(R13), R2 - p = appendp(p); - p->as = AMOVW; - p->from.type = D_CONST; - p->from.reg = 13; - p->from.offset = 4 + autoffset; - p->to.type = D_REG; - p->to.reg = 2; - - // MOVW $0, R3 - p = appendp(p); - p->as = AMOVW; - p->from.type = D_CONST; - p->from.offset = 0; - p->to.type = D_REG; - p->to.reg = 3; - - // L: - // MOVW.P R3, 0(R1) +4 - // CMP R1, R2 - // BNE L - p = pl = appendp(p); - p->as = AMOVW; - p->from.type = D_REG; - p->from.reg = 3; - p->to.type = D_OREG; - p->to.reg = 1; - p->to.offset = 4; - p->scond |= C_PBIT; - - p = appendp(p); - p->as = ACMP; - p->from.type = D_REG; - p->from.reg = 1; - p->reg = 2; - - p = appendp(p); - p->as = ABNE; - p->to.type = D_BRANCH; - p->cond = pl; - } - } -} diff --git a/src/cmd/5l/prof.c b/src/cmd/5l/prof.c deleted file mode 100644 index 225a52435..000000000 --- a/src/cmd/5l/prof.c +++ /dev/null @@ -1,211 +0,0 @@ -// 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) -{ -#ifdef NOTDEF // 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_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 = 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 = 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 = 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; - 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) { - 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 deleted file mode 100644 index de6481c71..000000000 --- a/src/cmd/5l/softfloat.c +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "l.h" -#include "../ld/lib.h" - -// Software floating point. - -void -softfloat(void) -{ - Prog *p, *next, *psfloat; - Sym *symsfloat; - int wasfloat; - - if(!debug['F']) - return; - - symsfloat = lookup("_sfloat", 0); - psfloat = P; - if(symsfloat->type == STEXT) - 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: - case ASQRTF: - case ASQRTD: - case AABSF: - case AABSD: - goto soft; - - default: - goto notsoft; - - 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->line = next->line; - - p = next; - wasfloat = 1; - } - break; - - notsoft: - wasfloat = 0; - } - } - } -} diff --git a/src/cmd/5l/span.c b/src/cmd/5l/span.c deleted file mode 100644 index e7cc0b4b1..000000000 --- a/src/cmd/5l/span.c +++ /dev/null @@ -1,937 +0,0 @@ -// Inferno utils/5l/span.c -// http://code.google.com/p/inferno-os/source/browse/utils/5l/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. - -// Instruction layout. - -#include "l.h" -#include "../ld/lib.h" - -static struct { - uint32 start; - uint32 size; - uint32 extra; -} pool; - -int checkpool(Prog*, int); -int flushpool(Prog*, int, int); - -int -isbranch(Prog *p) -{ - int as = p->as; - return (as >= ABEQ && as <= ABLE) || as == AB || as == ABL || as == ABX; -} - -static int -scan(Prog *op, Prog *p, int c) -{ - Prog *q; - - for(q = op->link; q != p && q != P; q = q->link){ - q->pc = c; - c += oplook(q)->size; - nocache(q); - } - return c; -} - -/* size of a case statement including jump table */ -static int32 -casesz(Prog *p) -{ - int jt = 0; - int32 n = 0; - Optab *o; - - for( ; p != P; p = p->link){ - if(p->as == ABCASE) - jt = 1; - else if(jt) - break; - o = oplook(p); - n += o->size; - } - return n; -} - -void -span(void) -{ - Prog *p, *op; - Optab *o; - int m, bflag, i, v; - int32 c, otxt, out[6]; - Section *sect; - uchar *bp; - Sym *sub, *gmsym; - - if(debug['v']) - Bprint(&bso, "%5.2f span\n", cputime()); - Bflush(&bso); - - sect = addsection(&segtext, ".text", 05); - lookup("text", 0)->sect = sect; - lookup("etext", 0)->sect = sect; - - bflag = 0; - c = INITTEXT; - otxt = c; - for(cursym = textp; cursym != nil; cursym = cursym->next) { - cursym->sect = sect; - p = cursym->text; - if(p == P || p->link == P) { // handle external functions and ELF section symbols - if(cursym->type & SSUB) - continue; - if(cursym->align != 0) - c = rnd(c, cursym->align); - cursym->value = 0; - for(sub = cursym; sub != S; sub = sub->sub) { - sub->value += c; - for(p = sub->text; p != P; p = p->link) - p->pc += sub->value; - } - c += cursym->size; - continue; - } - p->pc = c; - cursym->value = c; - - 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; - - for(op = p, p = p->link; p != P; op = p, p = p->link) { - curp = p; - p->pc = c; - o = oplook(p); - m = o->size; - // must check literal pool here in case p generates many instructions - if(blitrl){ - if(checkpool(op, p->as == ACASE ? casesz(p) : m)) - c = p->pc = scan(op, p, c); - } - if(m == 0 && (p->as != AFUNCDATA && p->as != APCDATA)) { - 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) - 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); - c += m; - } - if(blitrl){ - if(checkpool(op, 0)) - c = scan(op, P, c); - } - cursym->size = c - cursym->value; - } - - /* - * if any procedure is large enough to - * generate a large SBRA branch, then - * generate extra passes putting branches - * around jmps to fix. this is rare. - */ - while(bflag) { - if(debug['v']) - Bprint(&bso, "%5.2f span1\n", cputime()); - bflag = 0; - c = INITTEXT; - for(cursym = textp; cursym != nil; cursym = cursym->next) { - if(!cursym->text || !cursym->text->link) - continue; - cursym->value = c; - for(p = cursym->text; p != P; p = p->link) { - curp = p; - p->pc = c; - 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 && (p->as != AFUNCDATA && p->as != APCDATA)) { - 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; - } - c += m; - } - cursym->size = c - cursym->value; - } - } - - 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. - */ - gmsym = S; - if(linkmode == LinkExternal) - gmsym = lookup("runtime.tlsgm", 0); - for(cursym = textp; cursym != nil; cursym = cursym->next) { - p = cursym->text; - if(p == P || p->link == P) - continue; - autosize = p->to.offset + 4; - symgrow(cursym, cursym->size); - - bp = cursym->p; - for(p = p->link; p != P; p = p->link) { - pc = p->pc; - curp = p; - o = oplook(p); - asmout(p, o, out, gmsym); - for(i=0; isize/4; i++) { - v = out[i]; - *bp++ = v; - *bp++ = v>>8; - *bp++ = v>>16; - *bp++ = v>>24; - } - } - } - sect->vaddr = INITTEXT; - sect->len = c - INITTEXT; -} - -/* - * when the first reference to the literal pool threatens - * to go out of range of a 12-bit PC-relative offset, - * drop the pool now, and branch round it. - * this happens only in extended basic blocks that exceed 4k. - */ -int -checkpool(Prog *p, int sz) -{ - if(pool.size >= 0xffc || immaddr((p->pc+sz+4)+4+pool.size - pool.start+8) == 0) - return flushpool(p, 1, 0); - else if(p->link == P) - return flushpool(p, 2, 0); - return 0; -} - -int -flushpool(Prog *p, int skip, int force) -{ - Prog *q; - - if(blitrl) { - if(skip){ - 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; - q->cond = p->link; - q->link = blitrl; - q->line = p->line; - blitrl = q; - } - else if(!force && (p->pc+pool.size-pool.start < 2048)) - return 0; - elitrl->link = p->link; - p->link = blitrl; - // BUG(minux): how to correctly handle line number for constant pool entries? - // for now, we set line number to the last instruction preceding them at least - // this won't bloat the .debug_line tables - while(blitrl) { - blitrl->line = p->line; - blitrl = blitrl->link; - } - blitrl = 0; /* BUG: should refer back to values until out-of-range */ - elitrl = 0; - pool.size = 0; - pool.start = 0; - pool.extra = 0; - return 1; - } - return 0; -} - -void -addpool(Prog *p, Adr *a) -{ - Prog *q, t; - int c; - - c = aclass(a); - - t = zprg; - t.as = AWORD; - - switch(c) { - default: - t.to = *a; - if(flag_shared && t.to.sym != S) - t.pcrel = p; - break; - - case C_SROREG: - case C_LOREG: - case C_ROREG: - case C_FOREG: - case C_SOREG: - case C_HOREG: - case C_FAUTO: - case C_SAUTO: - case C_LAUTO: - case C_LACON: - t.to.type = D_CONST; - t.to.offset = instoffset; - break; - } - - if(t.pcrel == P) { - for(q = blitrl; q != P; q = q->link) /* could hash on t.t0.offset */ - if(q->pcrel == P && memcmp(&q->to, &t.to, sizeof(t.to)) == 0) { - p->cond = q; - return; - } - } - - q = prg(); - *q = t; - q->pc = pool.size; - - if(blitrl == P) { - blitrl = q; - pool.start = p->pc; - q->align = 4; - } else - elitrl->link = q; - elitrl = q; - pool.size += 4; - - p->cond = q; -} - -void -xdefine(char *p, int t, int32 v) -{ - Sym *s; - - s = lookup(p, 0); - s->type = t; - s->value = v; - s->reachable = 1; - s->special = 1; -} - -int32 -regoff(Adr *a) -{ - - instoffset = 0; - aclass(a); - return instoffset; -} - -int32 -immrot(uint32 v) -{ - int i; - - for(i=0; i<16; i++) { - if((v & ~0xff) == 0) - return (i<<8) | v | (1<<25); - v = (v<<2) | (v>>30); - } - return 0; -} - -int32 -immaddr(int32 v) -{ - if(v >= 0 && v <= 0xfff) - return (v & 0xfff) | - (1<<24) | /* pre indexing */ - (1<<23); /* pre indexing, up */ - if(v >= -0xfff && v < 0) - return (-v & 0xfff) | - (1<<24); /* pre indexing */ - return 0; -} - -int -immfloat(int32 v) -{ - return (v & 0xC03) == 0; /* offset will fit in floating-point load/store */ -} - -int -immhalf(int32 v) -{ - if(v >= 0 && v <= 0xff) - return v| - (1<<24)| /* pre indexing */ - (1<<23); /* pre indexing, up */ - if(v >= -0xff && v < 0) - return (-v & 0xff)| - (1<<24); /* pre indexing */ - return 0; -} - -int32 -symaddr(Sym *s) -{ - if(!s->reachable) - diag("unreachable symbol in symaddr - %s", s->name); - return s->value; -} - -int -aclass(Adr *a) -{ - Sym *s; - int t; - - switch(a->type) { - case D_NONE: - return C_NONE; - - case D_REG: - return C_REG; - - case D_REGREG: - return C_REGREG; - - case D_REGREG2: - return C_REGREG2; - - case D_SHIFT: - return C_SHIFT; - - case D_FREG: - return C_FREG; - - case D_FPCR: - return C_FCR; - - case D_OREG: - switch(a->name) { - case D_EXTERN: - case D_STATIC: - if(a->sym == 0 || a->sym->name == 0) { - print("null sym external\n"); - print("%D\n", a); - return C_GOK; - } - instoffset = 0; // s.b. unused but just in case - return C_ADDR; - - case D_AUTO: - instoffset = autosize + a->offset; - t = immaddr(instoffset); - if(t){ - if(immhalf(instoffset)) - return immfloat(t) ? C_HFAUTO : C_HAUTO; - if(immfloat(t)) - return C_FAUTO; - return C_SAUTO; - } - return C_LAUTO; - - case D_PARAM: - instoffset = autosize + a->offset + 4L; - t = immaddr(instoffset); - if(t){ - if(immhalf(instoffset)) - return immfloat(t) ? C_HFAUTO : C_HAUTO; - if(immfloat(t)) - return C_FAUTO; - return C_SAUTO; - } - return C_LAUTO; - case D_NONE: - instoffset = a->offset; - t = immaddr(instoffset); - if(t) { - if(immhalf(instoffset)) /* n.b. that it will also satisfy immrot */ - return immfloat(t) ? C_HFOREG : C_HOREG; - if(immfloat(t)) - return C_FOREG; /* n.b. that it will also satisfy immrot */ - t = immrot(instoffset); - if(t) - return C_SROREG; - if(immhalf(instoffset)) - return C_HOREG; - return C_SOREG; - } - t = immrot(instoffset); - if(t) - return C_ROREG; - return C_LOREG; - } - return C_GOK; - - case D_PSR: - return C_PSR; - - case D_OCONST: - switch(a->name) { - case D_EXTERN: - case D_STATIC: - instoffset = 0; // s.b. unused but just in case - return C_ADDR; - } - return C_GOK; - - case D_FCONST: - 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: - switch(a->name) { - - case D_NONE: - instoffset = a->offset; - if(a->reg != NREG) - goto aconsize; - - t = immrot(instoffset); - if(t) - return C_RCON; - t = immrot(~instoffset); - if(t) - return C_NCON; - return C_LCON; - - case D_EXTERN: - case D_STATIC: - s = a->sym; - if(s == S) - break; - instoffset = 0; // s.b. unused but just in case - return C_LCONADDR; - - case D_AUTO: - instoffset = autosize + a->offset; - goto aconsize; - - case D_PARAM: - instoffset = autosize + a->offset + 4L; - aconsize: - t = immrot(instoffset); - if(t) - return C_RACON; - return C_LACON; - } - return C_GOK; - - case D_BRANCH: - return C_SBRA; - } - return C_GOK; -} - -Optab* -oplook(Prog *p) -{ - int a1, a2, a3, r; - char *c1, *c3; - Optab *o, *e; - - a1 = p->optab; - if(a1) - return optab+(a1-1); - a1 = p->from.class; - if(a1 == 0) { - a1 = aclass(&p->from) + 1; - p->from.class = a1; - } - a1--; - a3 = p->to.class; - if(a3 == 0) { - a3 = aclass(&p->to) + 1; - p->to.class = a3; - } - a3--; - a2 = C_NONE; - if(p->reg != NREG) - a2 = C_REG; - r = p->as; - o = oprange[r].start; - if(o == 0) { - a1 = opcross[repop[r]][a1][a2][a3]; - if(a1) { - p->optab = a1+1; - return optab+a1; - } - o = oprange[r].stop; /* just generate an error */ - } - if(debug['O']) { - print("oplook %A %O %O %O\n", - (int)p->as, a1, a2, a3); - print(" %d %d\n", p->from.type, p->to.type); - } - e = oprange[r].stop; - c1 = xcmp[a1]; - c3 = xcmp[a3]; - for(; oa2 == a2) - if(c1[o->a1]) - if(c3[o->a3]) { - p->optab = (o-optab)+1; - return o; - } - diag("illegal combination %A %O %O %O, %d %d", - p->as, a1, a2, a3, p->from.type, p->to.type); - prasm(p); - if(o == 0) - o = optab; - return o; -} - -int -cmp(int a, int b) -{ - - if(a == b) - return 1; - switch(a) { - case C_LCON: - if(b == C_RCON || b == C_NCON) - return 1; - break; - case C_LACON: - if(b == C_RACON) - return 1; - break; - case C_LFCON: - if(b == C_ZFCON || b == C_SFCON) - return 1; - break; - - case C_HFAUTO: - return b == C_HAUTO || b == C_FAUTO; - case C_FAUTO: - case C_HAUTO: - return b == C_HFAUTO; - case C_SAUTO: - return cmp(C_HFAUTO, b); - case C_LAUTO: - return cmp(C_SAUTO, b); - - case C_HFOREG: - return b == C_HOREG || b == C_FOREG; - case C_FOREG: - case C_HOREG: - return b == C_HFOREG; - case C_SROREG: - return cmp(C_SOREG, b) || cmp(C_ROREG, b); - case C_SOREG: - case C_ROREG: - return b == C_SROREG || cmp(C_HFOREG, b); - case C_LOREG: - return cmp(C_SROREG, b); - - case C_LBRA: - if(b == C_SBRA) - return 1; - break; - - case C_HREG: - return cmp(C_SP, b) || cmp(C_PC, b); - - } - return 0; -} - -int -ocmp(const void *a1, const void *a2) -{ - Optab *p1, *p2; - int n; - - p1 = (Optab*)a1; - p2 = (Optab*)a2; - n = p1->as - p2->as; - if(n) - return n; - n = p1->a1 - p2->a1; - if(n) - return n; - n = p1->a2 - p2->a2; - if(n) - return n; - n = p1->a3 - p2->a3; - if(n) - return n; - return 0; -} - -void -buildop(void) -{ - int i, n, r; - - for(i=0; i= 32 || x >= nelem(opcross)) { - diag("assumptions fail in buildrep"); - errorexit(); - } - repop[as] = x; - p = (opcross + x); - s = oprange[as].start; - e = oprange[as].stop; - for(o=e-1; o>=s; o--) { - n = o-optab; - for(a2=0; a2<2; a2++) { - if(a2) { - if(o->a2 == C_NONE) - continue; - } else - if(o->a2 != C_NONE) - continue; - for(a1=0; a1<32; a1++) { - if(!xcmp[a1][o->a1]) - continue; - for(a3=0; a3<32; a3++) - if(xcmp[a3][o->a3]) - (*p)[a1][a2][a3] = n; - } - } - } - oprange[as].start = 0; -} -*/ diff --git a/src/cmd/6a/a.h b/src/cmd/6a/a.h index 5c7868070..b3fb0bb19 100644 --- a/src/cmd/6a/a.h +++ b/src/cmd/6a/a.h @@ -29,9 +29,9 @@ // THE SOFTWARE. #include +#include #include "../6l/6.out.h" - #ifndef EXTERN #define EXTERN extern #endif @@ -45,10 +45,8 @@ typedef struct Sym Sym; typedef struct Ref Ref; -typedef struct Gen Gen; typedef struct Io Io; -typedef struct Hist Hist; -typedef struct Gen2 Gen2; +typedef struct Addr2 Addr2; #define MAXALIGN 7 #define FPCHIP 1 @@ -97,36 +95,11 @@ struct Io }; #define I ((Io*)0) -EXTERN struct -{ - Sym* sym; - short type; -} h[NSYM]; - -struct Gen -{ - double dval; - char sval[8]; - vlong offset; - Sym* sym; - short type; - short index; - short scale; -}; -struct Gen2 -{ - Gen from; - Gen to; -}; - -struct Hist +struct Addr2 { - Hist* link; - char* name; - int32 line; - vlong offset; + Addr from; + Addr to; }; -#define H ((Hist*)0) enum { @@ -136,14 +109,11 @@ enum CPREPROC, }; - -EXTERN char debug[256]; +EXTERN int debug[256]; EXTERN Sym* hash[NHASH]; EXTERN char** Dlist; EXTERN int nDlist; -EXTERN Hist* ehist; EXTERN int newflag; -EXTERN Hist* hist; EXTERN char* hunk; EXTERN char** include; EXTERN Io* iofree; @@ -154,10 +124,9 @@ EXTERN int nerrors; EXTERN int32 nhunk; EXTERN int ninclude; EXTERN int32 nsymb; -EXTERN Gen nullgen; +EXTERN Addr nullgen; EXTERN char* outfile; EXTERN int pass; -EXTERN char* pathname; EXTERN int32 pc; EXTERN int peekc; EXTERN int32 stmtline; @@ -167,6 +136,8 @@ EXTERN int thechar; EXTERN char* thestring; EXTERN int32 thunk; EXTERN Biobuf obuf; +EXTERN Link* ctxt; +EXTERN Biobuf bstdout; void* alloc(int32); void* allocn(void*, int32, int32); @@ -187,12 +158,11 @@ void cinit(void); void checkscale(int); void pinit(char*); void cclean(void); -int isreg(Gen*); -void outcode(int, Gen2*); +int isreg(Addr*); +void outcode(int, Addr2*); void outhist(void); -void zaddr(Gen*, int); +void zaddr(Addr*, int); void zname(char*, int, int); -void ieeedtod(Ieee*, double); int filbuf(void); Sym* getsym(void); void domacro(void); diff --git a/src/cmd/6a/a.y b/src/cmd/6a/a.y index ed72916b2..6fd491067 100644 --- a/src/cmd/6a/a.y +++ b/src/cmd/6a/a.y @@ -40,8 +40,8 @@ vlong lval; double dval; char sval[8]; - Gen gen; - Gen2 gen2; + Addr addr; + Addr2 addr2; } %left '|' %left '^' @@ -58,10 +58,10 @@ %token LSCONST LSP %token LNAME LLAB LVAR %type con con2 expr pointer offset -%type mem imm imm2 reg nam rel rem rim rom omem nmem -%type nonnon nonrel nonrem rimnon rimrem remrim -%type spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8 spec9 -%type spec10 spec11 spec12 spec13 +%type mem imm imm2 reg nam rel rem rim rom omem nmem +%type nonnon nonrel nonrem rimnon rimrem remrim +%type spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8 spec9 +%type spec10 spec11 spec12 spec13 %% prog: | prog @@ -367,14 +367,12 @@ rel: if(pass == 2) yyerror("undefined label: %s", $1->name); $$.type = D_BRANCH; - $$.sym = $1; $$.offset = $2; } | LLAB offset { $$ = nullgen; $$.type = D_BRANCH; - $$.sym = $1; $$.offset = $1->value + $2; } @@ -444,31 +442,31 @@ imm: { $$ = nullgen; $$.type = D_SCONST; - memcpy($$.sval, $2, sizeof($$.sval)); + memcpy($$.u.sval, $2, sizeof($$.u.sval)); } | '$' LFCONST { $$ = nullgen; $$.type = D_FCONST; - $$.dval = $2; + $$.u.dval = $2; } | '$' '(' LFCONST ')' { $$ = nullgen; $$.type = D_FCONST; - $$.dval = $3; + $$.u.dval = $3; } | '$' '(' '-' LFCONST ')' { $$ = nullgen; $$.type = D_FCONST; - $$.dval = -$4; + $$.u.dval = -$4; } | '$' '-' LFCONST { $$ = nullgen; $$.type = D_FCONST; - $$.dval = -$3; + $$.u.dval = -$3; } mem: @@ -572,14 +570,14 @@ nam: { $$ = nullgen; $$.type = $4; - $$.sym = $1; + $$.sym = linklookup(ctxt, $1->name, 0); $$.offset = $2; } | LNAME '<' '>' offset '(' LSB ')' { $$ = nullgen; $$.type = D_STATIC; - $$.sym = $1; + $$.sym = linklookup(ctxt, $1->name, 1); $$.offset = $4; } diff --git a/src/cmd/6a/lex.c b/src/cmd/6a/lex.c index ab34e8220..167e6b6c1 100644 --- a/src/cmd/6a/lex.c +++ b/src/cmd/6a/lex.c @@ -57,56 +57,80 @@ pathchar(void) return '/'; } +int +Lconv(Fmt *fp) +{ + return linklinefmt(ctxt, fp); +} + +void +dodef(char *p) +{ + if(nDlist%8 == 0) + Dlist = allocn(Dlist, nDlist*sizeof(char *), + 8*sizeof(char *)); + Dlist[nDlist++] = p; +} + +LinkArch* thelinkarch = &linkamd64; + +void +usage(void) +{ + print("usage: %ca [options] file.c...\n", thechar); + flagprint(1); + errorexit(); +} + void main(int argc, char *argv[]) { char *p; - int c; thechar = '6'; thestring = "amd64"; + // Allow GOARCH=thestring or GOARCH=thestringsuffix, + // but not other values. + p = getgoarch(); + if(strncmp(p, thestring, strlen(thestring)) != 0) + sysfatal("cannot use %cc with GOARCH=%s", thechar, p); + if(strcmp(p, "amd64p32") == 0) + thelinkarch = &linkamd64p32; + + ctxt = linknew(thelinkarch); + ctxt->diag = yyerror; + ctxt->bso = &bstdout; + Binit(&bstdout, 1, OWRITE); + listinit6(); + fmtinstall('L', Lconv); + ensuresymb(NSYMB); memset(debug, 0, sizeof(debug)); cinit(); outfile = 0; setinclude("."); - ARGBEGIN { - default: - c = ARGC(); - if(c >= 0 && c < sizeof(debug)) - debug[c] = 1; - break; - - case 'o': - outfile = ARGF(); - break; + + flagfn1("D", "name[=value]: add #define", dodef); + flagfn1("I", "dir: add dir to include path", setinclude); + flagcount("S", "print assembly and machine code", &debug['S']); + flagcount("m", "debug preprocessor macros", &debug['m']); + flagstr("o", "file: set output file", &outfile); + flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath); - case 'D': - p = ARGF(); - if(p) { - if (nDlist%8 == 0) - Dlist = allocn(Dlist, nDlist*sizeof(char *), - 8*sizeof(char *)); - Dlist[nDlist++] = p; - } - break; + flagparse(&argc, &argv, usage); + ctxt->debugasm = debug['S']; - case 'I': - p = ARGF(); - setinclude(p); - break; - } ARGEND - if(*argv == 0) { - print("usage: %ca [-options] file.s\n", thechar); - errorexit(); - } + if(argc < 1) + usage(); if(argc > 1){ print("can't assemble multiple files\n"); errorexit(); } + if(assemble(argv[0])) errorexit(); + Bflush(&bstdout); exits(0); } @@ -145,30 +169,22 @@ assemble(char *file) errorexit(); } Binit(&obuf, of, OWRITE); + Bprint(&obuf, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion()); + Bprint(&obuf, "!\n"); - pass = 1; - pinit(file); - - Bprint(&obuf, "go object %s %s %s\n", getgoos(), thestring, getgoversion()); - - for(i=0; itype = itab[i].type; s->value = itab[i].value; } - - pathname = allocn(pathname, 0, 100); - if(getwd(pathname, 99) == 0) { - pathname = allocn(pathname, 100, 900); - if(getwd(pathname, 999) == 0) - strcpy(pathname, "/???"); - } } void @@ -1089,255 +1093,43 @@ syminit(Sym *s) void cclean(void) { - Gen2 g2; + Addr2 g2; g2.from = nullgen; g2.to = nullgen; outcode(AEND, &g2); - Bflush(&obuf); } -void -zname(char *n, int t, int s) -{ - - BPUTLE2(&obuf, ANAME); /* as(2) */ - BPUTC(&obuf, t); /* type */ - BPUTC(&obuf, s); /* sym */ - while(*n) { - BPUTC(&obuf, *n); - n++; - } - BPUTC(&obuf, 0); -} +static Prog *lastpc; void -zaddr(Gen *a, int s) +outcode(int a, Addr2 *g2) { - int32 l; - int i, t; - char *n; - Ieee e; - - t = 0; - if(a->index != D_NONE || a->scale != 0) - t |= T_INDEX; - if(a->offset != 0) { - t |= T_OFFSET; - l = a->offset; - if((vlong)l != a->offset) - t |= T_64; - } - if(s != 0) - t |= T_SYM; - - switch(a->type) { - default: - t |= T_TYPE; - break; - case D_FCONST: - t |= T_FCONST; - break; - case D_SCONST: - t |= T_SCONST; - break; - case D_NONE: - break; - } - BPUTC(&obuf, t); - - if(t & T_INDEX) { /* implies index, scale */ - BPUTC(&obuf, a->index); - BPUTC(&obuf, a->scale); - } - if(t & T_OFFSET) { /* implies offset */ - l = a->offset; - BPUTLE4(&obuf, l); - if(t & T_64) { - l = a->offset>>32; - BPUTLE4(&obuf, l); - } - } - if(t & T_SYM) /* implies sym */ - BPUTC(&obuf, s); - if(t & T_FCONST) { - ieeedtod(&e, a->dval); - l = e.l; - BPUTLE4(&obuf, l); - l = e.h; - BPUTLE4(&obuf, l); - return; - } - if(t & T_SCONST) { - n = a->sval; - for(i=0; itype); -} - -void -outcode(int a, Gen2 *g2) -{ - int sf, st, t; - Sym *s; - + Prog *p; + Plist *pl; + if(pass == 1) goto out; -jackpot: - sf = 0; - s = g2->from.sym; - while(s != S) { - sf = s->sym; - if(sf < 0 || sf >= NSYM) - sf = 0; - t = g2->from.type; - if(t == D_ADDR) - t = g2->from.index; - if(h[sf].type == t) - if(h[sf].sym == s) - break; - zname(s->name, t, sym); - s->sym = sym; - h[sym].sym = s; - h[sym].type = t; - sf = sym; - sym++; - if(sym >= NSYM) - sym = 1; - break; - } - st = 0; - s = g2->to.sym; - while(s != S) { - st = s->sym; - if(st < 0 || st >= NSYM) - st = 0; - t = g2->to.type; - if(t == D_ADDR) - t = g2->to.index; - if(h[st].type == t) - if(h[st].sym == s) - break; - zname(s->name, t, sym); - s->sym = sym; - h[sym].sym = s; - h[sym].type = t; - st = sym; - sym++; - if(sym >= NSYM) - sym = 1; - if(st == sf) - goto jackpot; - break; - } - BPUTLE2(&obuf, a); - BPUTLE4(&obuf, stmtline); - zaddr(&g2->from, sf); - zaddr(&g2->to, st); + p = malloc(sizeof *p); + memset(p, 0, sizeof *p); + p->as = a; + p->lineno = stmtline; + p->from = g2->from; + p->to = g2->to; + p->pc = pc; + + if(lastpc == nil) { + pl = linknewplist(ctxt); + pl->firstpc = p; + } else + lastpc->link = p; + lastpc = p; out: if(a != AGLOBL && a != ADATA) pc++; } -void -outhist(void) -{ - Gen g; - Hist *h; - char *p, *q, *op, c; - int n; - char *tofree; - static int first = 1; - static char *goroot, *goroot_final; - - if(first) { - // Decide whether we need to rewrite paths from $GOROOT to $GOROOT_FINAL. - first = 0; - goroot = getenv("GOROOT"); - goroot_final = getenv("GOROOT_FINAL"); - if(goroot == nil) - goroot = ""; - if(goroot_final == nil) - goroot_final = goroot; - if(strcmp(goroot, goroot_final) == 0) { - goroot = nil; - goroot_final = nil; - } - } - - tofree = nil; - - g = nullgen; - c = pathchar(); - for(h = hist; h != H; h = h->link) { - p = h->name; - if(p != nil && goroot != nil) { - n = strlen(goroot); - if(strncmp(p, goroot, strlen(goroot)) == 0 && p[n] == '/') { - tofree = smprint("%s%s", goroot_final, p+n); - p = tofree; - } - } - op = 0; - if(systemtype(Windows) && p && p[1] == ':'){ - c = p[2]; - } else if(p && p[0] != c && h->offset == 0 && pathname){ - if(systemtype(Windows) && pathname[1] == ':') { - op = p; - p = pathname; - c = p[2]; - } else if(pathname[0] == c){ - op = p; - p = pathname; - } - } - while(p) { - q = strchr(p, c); - if(q) { - n = q-p; - if(n == 0){ - n = 1; /* leading "/" */ - *p = '/'; /* don't emit "\" on windows */ - } - q++; - } else { - n = strlen(p); - q = 0; - } - if(n) { - BPUTLE2(&obuf, ANAME); - BPUTC(&obuf, D_FILE); /* type */ - BPUTC(&obuf, 1); /* sym */ - BPUTC(&obuf, '<'); - Bwrite(&obuf, p, n); - BPUTC(&obuf, 0); - } - p = q; - if(p == 0 && op) { - p = op; - op = 0; - } - } - g.offset = h->offset; - - BPUTLE2(&obuf, AHISTORY); - BPUTLE4(&obuf, h->line); - zaddr(&nullgen, 0); - zaddr(&g, 0); - - if(tofree) { - free(tofree); - tofree = nil; - } - } -} - #include "../cc/lexbody" #include "../cc/macbody" diff --git a/src/cmd/6a/y.tab.c b/src/cmd/6a/y.tab.c index 3e5058b9d..a4f0f74cc 100644 --- a/src/cmd/6a/y.tab.c +++ b/src/cmd/6a/y.tab.c @@ -1,21 +1,24 @@ -/* A Bison parser, made by GNU Bison 2.5. */ +/* A Bison parser, made by GNU Bison 2.3. */ -/* Bison implementation for Yacc-like parsers in C - - Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify +/* Skeleton implementation for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - + the Free Software Foundation; either version 2, or (at your option) + any later version. + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License - along with this program. If not, see . */ + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work @@ -26,7 +29,7 @@ special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. - + This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ @@ -44,7 +47,7 @@ #define YYBISON 1 /* Bison version. */ -#define YYBISON_VERSION "2.5" +#define YYBISON_VERSION "2.3" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -52,51 +55,11 @@ /* Pure parsers. */ #define YYPURE 0 -/* Push parsers. */ -#define YYPUSH 0 - -/* Pull parsers. */ -#define YYPULL 1 - /* Using locations. */ #define YYLSP_NEEDED 0 -/* Copy the first part of user declarations. */ - -/* Line 268 of yacc.c */ -#line 31 "a.y" - -#include -#include /* if we don't, bison will, and a.h re-#defines getc */ -#include -#include "a.h" -#include "../../pkg/runtime/funcdata.h" - - -/* Line 268 of yacc.c */ -#line 80 "y.tab.c" - -/* Enabling traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif - -/* Enabling verbose error messages. */ -#ifdef YYERROR_VERBOSE -# undef YYERROR_VERBOSE -# define YYERROR_VERBOSE 1 -#else -# define YYERROR_VERBOSE 0 -#endif - -/* Enabling the token table. */ -#ifndef YYTOKEN_TABLE -# define YYTOKEN_TABLE 0 -#endif - - /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE @@ -180,36 +143,60 @@ +/* Copy the first part of user declarations. */ +#line 31 "a.y" + +#include +#include /* if we don't, bison will, and a.h re-#defines getc */ +#include +#include "a.h" +#include "../../pkg/runtime/funcdata.h" + + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE -{ - -/* Line 293 of yacc.c */ #line 38 "a.y" - +{ Sym *sym; vlong lval; double dval; char sval[8]; - Gen gen; - Gen2 gen2; - - - -/* Line 293 of yacc.c */ -#line 201 "y.tab.c" -} YYSTYPE; -# define YYSTYPE_IS_TRIVIAL 1 + Addr addr; + Addr2 addr2; +} +/* Line 193 of yacc.c. */ +#line 187 "y.tab.c" + YYSTYPE; # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 #endif + /* Copy the second part of user declarations. */ -/* Line 343 of yacc.c */ -#line 213 "y.tab.c" +/* Line 216 of yacc.c. */ +#line 200 "y.tab.c" #ifdef short # undef short @@ -284,14 +271,14 @@ typedef short int yytype_int16; #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static int -YYID (int yyi) +YYID (int i) #else static int -YYID (yyi) - int yyi; +YYID (i) + int i; #endif { - return yyi; + return i; } #endif @@ -312,11 +299,11 @@ YYID (yyi) # define alloca _alloca # else # define YYSTACK_ALLOC alloca -# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ +# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) # include /* INFRINGES ON USER NAME SPACE */ -# ifndef EXIT_SUCCESS -# define EXIT_SUCCESS 0 +# ifndef _STDLIB_H +# define _STDLIB_H 1 # endif # endif # endif @@ -339,24 +326,24 @@ YYID (yyi) # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif -# if (defined __cplusplus && ! defined EXIT_SUCCESS \ +# if (defined __cplusplus && ! defined _STDLIB_H \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ -# ifndef EXIT_SUCCESS -# define EXIT_SUCCESS 0 +# ifndef _STDLIB_H +# define _STDLIB_H 1 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc -# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ +# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free -# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ +# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif @@ -372,9 +359,9 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */ /* A type that is properly aligned for any stack member. */ union yyalloc { - yytype_int16 yyss_alloc; - YYSTYPE yyvs_alloc; -}; + yytype_int16 yyss; + YYSTYPE yyvs; + }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) @@ -385,27 +372,6 @@ union yyalloc ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) -# define YYCOPY_NEEDED 1 - -/* Relocate STACK from its old location to the new one. The - local variables YYSIZE and YYSTACKSIZE give the old and new number of - elements in the stack, and YYPTR gives the new location of the - stack. Advance YYPTR to a properly aligned location for the next - stack. */ -# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ - do \ - { \ - YYSIZE_T yynewbytes; \ - YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ - Stack = &yyptr->Stack_alloc; \ - yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ - yyptr += yynewbytes / sizeof (*yyptr); \ - } \ - while (YYID (0)) - -#endif - -#if defined YYCOPY_NEEDED && YYCOPY_NEEDED /* Copy COUNT objects from FROM to TO. The source and destination do not overlap. */ # ifndef YYCOPY @@ -423,7 +389,24 @@ union yyalloc while (YYID (0)) # endif # endif -#endif /* !YYCOPY_NEEDED */ + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack, Stack, yysize); \ + Stack = &yyptr->Stack; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif /* YYFINAL -- State number of the termination state. */ #define YYFINAL 2 @@ -564,13 +547,13 @@ static const yytype_uint16 yyrline[] = 166, 173, 178, 183, 190, 198, 203, 211, 216, 223, 224, 227, 232, 242, 247, 257, 262, 267, 274, 282, 292, 296, 303, 308, 316, 325, 336, 337, 340, 341, - 342, 346, 350, 351, 354, 355, 358, 364, 373, 382, - 387, 392, 397, 402, 407, 412, 418, 426, 432, 443, - 449, 455, 461, 467, 475, 476, 479, 485, 491, 497, - 503, 512, 521, 530, 535, 540, 548, 558, 562, 571, - 578, 587, 590, 594, 600, 601, 605, 608, 609, 613, - 617, 621, 625, 631, 636, 641, 646, 653, 654, 658, - 662, 666, 670, 674, 678, 682, 686, 690 + 342, 346, 350, 351, 354, 355, 358, 364, 372, 380, + 385, 390, 395, 400, 405, 410, 416, 424, 430, 441, + 447, 453, 459, 465, 473, 474, 477, 483, 489, 495, + 501, 510, 519, 528, 533, 538, 546, 556, 560, 569, + 576, 585, 588, 592, 598, 599, 603, 606, 607, 611, + 615, 619, 623, 629, 634, 639, 644, 651, 652, 656, + 660, 664, 668, 672, 676, 680, 684, 688 }; #endif @@ -586,12 +569,11 @@ static const char *const yytname[] = "LTYPEF", "LCONST", "LFP", "LPC", "LSB", "LBREG", "LLREG", "LSREG", "LFREG", "LMREG", "LXREG", "LFCONST", "LSCONST", "LSP", "LNAME", "LLAB", "LVAR", "':'", "';'", "'='", "','", "'('", "')'", "'$'", "'~'", - "$accept", "prog", "$@1", "line", "$@2", "$@3", "inst", "nonnon", - "rimrem", "remrim", "rimnon", "nonrem", "nonrel", "spec1", "spec2", - "spec3", "spec4", "spec5", "spec6", "spec7", "spec8", "spec9", "spec10", - "spec11", "spec12", "spec13", "rem", "rom", "rim", "rel", "reg", "imm2", - "imm", "mem", "omem", "nmem", "nam", "offset", "pointer", "con", "con2", - "expr", 0 + "$accept", "prog", "@1", "line", "@2", "@3", "inst", "nonnon", "rimrem", + "remrim", "rimnon", "nonrem", "nonrel", "spec1", "spec2", "spec3", + "spec4", "spec5", "spec6", "spec7", "spec8", "spec9", "spec10", "spec11", + "spec12", "spec13", "rem", "rom", "rim", "rel", "reg", "imm2", "imm", + "mem", "omem", "nmem", "nam", "offset", "pointer", "con", "con2", "expr", 0 }; #endif @@ -647,8 +629,8 @@ static const yytype_uint8 yyr2[] = 3, 3, 3, 4, 4, 3, 3, 3 }; -/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM. - Performed when YYTABLE doesn't specify something else to do. Zero +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero means the default is an error. */ static const yytype_uint8 yydefact[] = { @@ -739,7 +721,8 @@ static const yytype_int16 yypgoto[] = /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which - number is the opposite. If YYTABLE_NINF, syntax error. */ + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ #define YYTABLE_NINF -1 static const yytype_uint16 yytable[] = { @@ -802,12 +785,6 @@ static const yytype_uint16 yytable[] = 177 }; -#define yypact_value_is_default(yystate) \ - ((yystate) == (-94)) - -#define yytable_value_is_error(yytable_value) \ - YYID (0) - static const yytype_int16 yycheck[] = { 10, 10, 13, 13, 10, 13, 66, 67, 10, 10, @@ -915,18 +892,9 @@ static const yytype_uint8 yystos[] = /* Like YYERROR except do call yyerror. This remains here temporarily to ease the transition to the new meaning of YYERROR, for GCC. - Once GCC version 2 has supplanted version 1, this can go. However, - YYFAIL appears to be in use. Nevertheless, it is formally deprecated - in Bison 2.4.2's NEWS entry, where a plan to phase it out is - discussed. */ + Once GCC version 2 has supplanted version 1, this can go. */ #define YYFAIL goto yyerrlab -#if defined YYFAIL - /* This is here to suppress warnings from the GCC cpp's - -Wunused-macros. Normally we don't worry about that warning, but - some users do, and we want to make it easy for users to remove - YYFAIL uses, which will produce warnings from Bison 2.5. */ -#endif #define YYRECOVERING() (!!yyerrstatus) @@ -936,6 +904,7 @@ do \ { \ yychar = (Token); \ yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ YYPOPSTACK (1); \ goto yybackup; \ } \ @@ -977,10 +946,19 @@ while (YYID (0)) #endif -/* This macro is provided for backward compatibility. */ +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ #ifndef YY_LOCATION_PRINT -# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif #endif @@ -1084,20 +1062,17 @@ yy_symbol_print (yyoutput, yytype, yyvaluep) #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void -yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +yy_stack_print (yytype_int16 *bottom, yytype_int16 *top) #else static void -yy_stack_print (yybottom, yytop) - yytype_int16 *yybottom; - yytype_int16 *yytop; +yy_stack_print (bottom, top) + yytype_int16 *bottom; + yytype_int16 *top; #endif { YYFPRINTF (stderr, "Stack now"); - for (; yybottom <= yytop; yybottom++) - { - int yybot = *yybottom; - YYFPRINTF (stderr, " %d", yybot); - } + for (; bottom <= top; ++bottom) + YYFPRINTF (stderr, " %d", *bottom); YYFPRINTF (stderr, "\n"); } @@ -1131,11 +1106,11 @@ yy_reduce_print (yyvsp, yyrule) /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { - YYFPRINTF (stderr, " $%d = ", yyi + 1); + fprintf (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], &(yyvsp[(yyi + 1) - (yynrhs)]) ); - YYFPRINTF (stderr, "\n"); + fprintf (stderr, "\n"); } } @@ -1172,6 +1147,7 @@ int yydebug; # define YYMAXDEPTH 10000 #endif + #if YYERROR_VERBOSE @@ -1274,142 +1250,115 @@ yytnamerr (char *yyres, const char *yystr) } # endif -/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message - about the unexpected token YYTOKEN for the state stack whose top is - YYSSP. - - Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is - not large enough to hold the message. In that case, also set - *YYMSG_ALLOC to the required number of bytes. Return 2 if the - required number of bytes is too large to store. */ -static int -yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, - yytype_int16 *yyssp, int yytoken) +/* Copy into YYRESULT an error message about the unexpected token + YYCHAR while in state YYSTATE. Return the number of bytes copied, + including the terminating null byte. If YYRESULT is null, do not + copy anything; just return the number of bytes that would be + copied. As a special case, return 0 if an ordinary "syntax error" + message will do. Return YYSIZE_MAXIMUM if overflow occurs during + size calculation. */ +static YYSIZE_T +yysyntax_error (char *yyresult, int yystate, int yychar) { - YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]); - YYSIZE_T yysize = yysize0; - YYSIZE_T yysize1; - enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; - /* Internationalized format string. */ - const char *yyformat = 0; - /* Arguments of yyformat. */ - char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; - /* Number of reported tokens (one for the "unexpected", one per - "expected"). */ - int yycount = 0; - - /* There are many possibilities here to consider: - - Assume YYFAIL is not used. It's too flawed to consider. See - - for details. YYERROR is fine as it does not invoke this - function. - - If this state is a consistent state with a default action, then - the only way this function was invoked is if the default action - is an error action. In that case, don't check for expected - tokens because there are none. - - The only way there can be no lookahead present (in yychar) is if - this state is a consistent state with a default action. Thus, - detecting the absence of a lookahead is sufficient to determine - that there is no unexpected or expected token to report. In that - case, just report a simple "syntax error". - - Don't assume there isn't a lookahead just because this state is a - consistent state with a default action. There might have been a - previous inconsistent state, consistent state with a non-default - action, or user semantic action that manipulated yychar. - - Of course, the expected token list depends on states to have - correct lookahead information, and it depends on the parser not - to perform extra reductions after fetching a lookahead from the - scanner and before detecting a syntax error. Thus, state merging - (from LALR or IELR) and default reductions corrupt the expected - token list. However, the list is correct for canonical LR with - one exception: it will still contain any token that will not be - accepted due to an error action in a later state. - */ - if (yytoken != YYEMPTY) - { - int yyn = yypact[*yyssp]; - yyarg[yycount++] = yytname[yytoken]; - if (!yypact_value_is_default (yyn)) - { - /* Start YYX at -YYN if negative to avoid negative indexes in - YYCHECK. In other words, skip the first -YYN actions for - this state because they are default actions. */ - int yyxbegin = yyn < 0 ? -yyn : 0; - /* Stay within bounds of both yycheck and yytname. */ - int yychecklim = YYLAST - yyn + 1; - int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; - int yyx; - - for (yyx = yyxbegin; yyx < yyxend; ++yyx) - if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR - && !yytable_value_is_error (yytable[yyx + yyn])) - { - if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) - { - yycount = 1; - yysize = yysize0; - break; - } - yyarg[yycount++] = yytname[yyx]; - yysize1 = yysize + yytnamerr (0, yytname[yyx]); - if (! (yysize <= yysize1 - && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) - return 2; - yysize = yysize1; - } - } - } + int yyn = yypact[yystate]; - switch (yycount) - { -# define YYCASE_(N, S) \ - case N: \ - yyformat = S; \ - break - YYCASE_(0, YY_("syntax error")); - YYCASE_(1, YY_("syntax error, unexpected %s")); - YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); - YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); - YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); - YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); -# undef YYCASE_ - } + if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) + return 0; + else + { + int yytype = YYTRANSLATE (yychar); + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + int yysize_overflow = 0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int yyx; + +# if 0 + /* This is so xgettext sees the translatable formats that are + constructed on the fly. */ + YY_("syntax error, unexpected %s"); + YY_("syntax error, unexpected %s, expecting %s"); + YY_("syntax error, unexpected %s, expecting %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); +# endif + char *yyfmt; + char const *yyf; + static char const yyunexpected[] = "syntax error, unexpected %s"; + static char const yyexpecting[] = ", expecting %s"; + static char const yyor[] = " or %s"; + char yyformat[sizeof yyunexpected + + sizeof yyexpecting - 1 + + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) + * (sizeof yyor - 1))]; + char const *yyprefix = yyexpecting; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 1; + + yyarg[0] = yytname[yytype]; + yyfmt = yystpcpy (yyformat, yyunexpected); + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + yyformat[sizeof yyunexpected - 1] = '\0'; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + yyfmt = yystpcpy (yyfmt, yyprefix); + yyprefix = yyor; + } - yysize1 = yysize + yystrlen (yyformat); - if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) - return 2; - yysize = yysize1; + yyf = YY_(yyformat); + yysize1 = yysize + yystrlen (yyf); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; - if (*yymsg_alloc < yysize) - { - *yymsg_alloc = 2 * yysize; - if (! (yysize <= *yymsg_alloc - && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) - *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; - return 1; - } + if (yysize_overflow) + return YYSIZE_MAXIMUM; - /* Avoid sprintf, as that infringes on the user's name space. - Don't have undefined behavior even if the translation - produced a string with the wrong number of "%s"s. */ - { - char *yyp = *yymsg; - int yyi = 0; - while ((*yyp = *yyformat) != '\0') - if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) - { - yyp += yytnamerr (yyp, yyarg[yyi++]); - yyformat += 2; - } - else - { - yyp++; - yyformat++; - } - } - return 0; + if (yyresult) + { + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + char *yyp = yyresult; + int yyi = 0; + while ((*yyp = *yyf) != '\0') + { + if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyf += 2; + } + else + { + yyp++; + yyf++; + } + } + } + return yysize; + } } #endif /* YYERROR_VERBOSE */ + /*-----------------------------------------------. | Release the memory associated to this symbol. | @@ -1441,9 +1390,10 @@ yydestruct (yymsg, yytype, yyvaluep) break; } } - + /* Prevent warnings from -Wmissing-prototypes. */ + #ifdef YYPARSE_PARAM #if defined __STDC__ || defined __cplusplus int yyparse (void *YYPARSE_PARAM); @@ -1459,16 +1409,18 @@ int yyparse (); #endif /* ! YYPARSE_PARAM */ -/* The lookahead symbol. */ + +/* The look-ahead symbol. */ int yychar; -/* The semantic value of the lookahead symbol. */ +/* The semantic value of the look-ahead symbol. */ YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; + /*----------. | yyparse. | `----------*/ @@ -1495,37 +1447,14 @@ yyparse () #endif #endif { - int yystate; - /* Number of tokens to shift before error messages enabled. */ - int yyerrstatus; - - /* The stacks and their tools: - `yyss': related to states. - `yyvs': related to semantic values. - - Refer to the stacks thru separate pointers, to allow yyoverflow - to reallocate them elsewhere. */ - - /* The state stack. */ - yytype_int16 yyssa[YYINITDEPTH]; - yytype_int16 *yyss; - yytype_int16 *yyssp; - - /* The semantic value stack. */ - YYSTYPE yyvsa[YYINITDEPTH]; - YYSTYPE *yyvs; - YYSTYPE *yyvsp; - - YYSIZE_T yystacksize; - + + int yystate; int yyn; int yyresult; - /* Lookahead token as an internal (translated) token number. */ - int yytoken; - /* The variables used to return semantic value and location from the - action routines. */ - YYSTYPE yyval; - + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Look-ahead token as an internal (translated) token number. */ + int yytoken = 0; #if YYERROR_VERBOSE /* Buffer for error messages, and its allocated size. */ char yymsgbuf[128]; @@ -1533,28 +1462,51 @@ yyparse () YYSIZE_T yymsg_alloc = sizeof yymsgbuf; #endif + /* Three stacks and their tools: + `yyss': related to states, + `yyvs': related to semantic values, + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss = yyssa; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + YYSTYPE *yyvsp; + + + #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + YYSIZE_T yystacksize = YYINITDEPTH; + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + + /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; - yytoken = 0; - yyss = yyssa; - yyvs = yyvsa; - yystacksize = YYINITDEPTH; - YYDPRINTF ((stderr, "Starting parse\n")); yystate = 0; yyerrstatus = 0; yynerrs = 0; - yychar = YYEMPTY; /* Cause a token to be read. */ + yychar = YYEMPTY; /* Cause a token to be read. */ /* Initialize stack pointers. Waste one element of value and location stack so that they stay on the same level as the state stack. The wasted elements are never initialized. */ + yyssp = yyss; yyvsp = yyvs; @@ -1584,6 +1536,7 @@ yyparse () YYSTYPE *yyvs1 = yyvs; yytype_int16 *yyss1 = yyss; + /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might @@ -1591,6 +1544,7 @@ yyparse () yyoverflow (YY_("memory exhausted"), &yyss1, yysize * sizeof (*yyssp), &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); yyss = yyss1; @@ -1613,8 +1567,9 @@ yyparse () (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); if (! yyptr) goto yyexhaustedlab; - YYSTACK_RELOCATE (yyss_alloc, yyss); - YYSTACK_RELOCATE (yyvs_alloc, yyvs); + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); + # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); @@ -1625,6 +1580,7 @@ yyparse () yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; + YYDPRINTF ((stderr, "Stack size increased to %lu\n", (unsigned long int) yystacksize)); @@ -1634,9 +1590,6 @@ yyparse () YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - if (yystate == YYFINAL) - YYACCEPT; - goto yybackup; /*-----------. @@ -1645,16 +1598,16 @@ yyparse () yybackup: /* Do appropriate processing given the current state. Read a - lookahead token if we need one and don't already have one. */ + look-ahead token if we need one and don't already have one. */ - /* First try to decide what to do without reference to lookahead token. */ + /* First try to decide what to do without reference to look-ahead token. */ yyn = yypact[yystate]; - if (yypact_value_is_default (yyn)) + if (yyn == YYPACT_NINF) goto yydefault; - /* Not known => get a lookahead token if don't already have one. */ + /* Not known => get a look-ahead token if don't already have one. */ - /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token: ")); @@ -1680,22 +1633,26 @@ yybackup: yyn = yytable[yyn]; if (yyn <= 0) { - if (yytable_value_is_error (yyn)) - goto yyerrlab; + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; yyn = -yyn; goto yyreduce; } + if (yyn == YYFINAL) + YYACCEPT; + /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; - /* Shift the lookahead token. */ + /* Shift the look-ahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); - /* Discard the shifted token. */ - yychar = YYEMPTY; + /* Discard the shifted token unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; yystate = yyn; *++yyvsp = yylval; @@ -1735,8 +1692,6 @@ yyreduce: switch (yyn) { case 3: - -/* Line 1806 of yacc.c */ #line 68 "a.y" { stmtline = lineno; @@ -1744,8 +1699,6 @@ yyreduce: break; case 5: - -/* Line 1806 of yacc.c */ #line 75 "a.y" { if((yyvsp[(1) - (2)].sym)->value != pc) @@ -1755,8 +1708,6 @@ yyreduce: break; case 7: - -/* Line 1806 of yacc.c */ #line 82 "a.y" { (yyvsp[(1) - (2)].sym)->type = LLAB; @@ -1765,8 +1716,6 @@ yyreduce: break; case 12: - -/* Line 1806 of yacc.c */ #line 93 "a.y" { (yyvsp[(1) - (3)].sym)->type = LVAR; @@ -1775,8 +1724,6 @@ yyreduce: break; case 13: - -/* Line 1806 of yacc.c */ #line 98 "a.y" { if((yyvsp[(1) - (3)].sym)->value != (yyvsp[(3) - (3)].lval)) @@ -1786,622 +1733,490 @@ yyreduce: break; case 14: - -/* Line 1806 of yacc.c */ #line 103 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 15: - -/* Line 1806 of yacc.c */ #line 104 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 16: - -/* Line 1806 of yacc.c */ #line 105 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 17: - -/* Line 1806 of yacc.c */ #line 106 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 18: - -/* Line 1806 of yacc.c */ #line 107 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 19: - -/* Line 1806 of yacc.c */ #line 108 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 20: - -/* Line 1806 of yacc.c */ #line 109 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 21: - -/* Line 1806 of yacc.c */ #line 110 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 22: - -/* Line 1806 of yacc.c */ #line 111 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 23: - -/* Line 1806 of yacc.c */ #line 112 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 24: - -/* Line 1806 of yacc.c */ #line 113 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 25: - -/* Line 1806 of yacc.c */ #line 114 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 26: - -/* Line 1806 of yacc.c */ #line 115 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 27: - -/* Line 1806 of yacc.c */ #line 116 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 28: - -/* Line 1806 of yacc.c */ #line 117 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 29: - -/* Line 1806 of yacc.c */ #line 118 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 30: - -/* Line 1806 of yacc.c */ #line 119 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 31: - -/* Line 1806 of yacc.c */ #line 120 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 32: - -/* Line 1806 of yacc.c */ #line 121 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 33: - -/* Line 1806 of yacc.c */ #line 124 "a.y" { - (yyval.gen2).from = nullgen; - (yyval.gen2).to = nullgen; + (yyval.addr2).from = nullgen; + (yyval.addr2).to = nullgen; } break; case 34: - -/* Line 1806 of yacc.c */ #line 129 "a.y" { - (yyval.gen2).from = nullgen; - (yyval.gen2).to = nullgen; + (yyval.addr2).from = nullgen; + (yyval.addr2).to = nullgen; } break; case 35: - -/* Line 1806 of yacc.c */ #line 136 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (3)].gen); - (yyval.gen2).to = (yyvsp[(3) - (3)].gen); + (yyval.addr2).from = (yyvsp[(1) - (3)].addr); + (yyval.addr2).to = (yyvsp[(3) - (3)].addr); } break; case 36: - -/* Line 1806 of yacc.c */ #line 143 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (3)].gen); - (yyval.gen2).to = (yyvsp[(3) - (3)].gen); + (yyval.addr2).from = (yyvsp[(1) - (3)].addr); + (yyval.addr2).to = (yyvsp[(3) - (3)].addr); } break; case 37: - -/* Line 1806 of yacc.c */ #line 150 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (2)].gen); - (yyval.gen2).to = nullgen; + (yyval.addr2).from = (yyvsp[(1) - (2)].addr); + (yyval.addr2).to = nullgen; } break; case 38: - -/* Line 1806 of yacc.c */ #line 155 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (1)].gen); - (yyval.gen2).to = nullgen; + (yyval.addr2).from = (yyvsp[(1) - (1)].addr); + (yyval.addr2).to = nullgen; } break; case 39: - -/* Line 1806 of yacc.c */ #line 162 "a.y" { - (yyval.gen2).from = nullgen; - (yyval.gen2).to = (yyvsp[(2) - (2)].gen); + (yyval.addr2).from = nullgen; + (yyval.addr2).to = (yyvsp[(2) - (2)].addr); } break; case 40: - -/* Line 1806 of yacc.c */ #line 167 "a.y" { - (yyval.gen2).from = nullgen; - (yyval.gen2).to = (yyvsp[(1) - (1)].gen); + (yyval.addr2).from = nullgen; + (yyval.addr2).to = (yyvsp[(1) - (1)].addr); } break; case 41: - -/* Line 1806 of yacc.c */ #line 174 "a.y" { - (yyval.gen2).from = nullgen; - (yyval.gen2).to = (yyvsp[(2) - (2)].gen); + (yyval.addr2).from = nullgen; + (yyval.addr2).to = (yyvsp[(2) - (2)].addr); } break; case 42: - -/* Line 1806 of yacc.c */ #line 179 "a.y" { - (yyval.gen2).from = nullgen; - (yyval.gen2).to = (yyvsp[(1) - (1)].gen); + (yyval.addr2).from = nullgen; + (yyval.addr2).to = (yyvsp[(1) - (1)].addr); } break; case 43: - -/* Line 1806 of yacc.c */ #line 184 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (3)].gen); - (yyval.gen2).to = (yyvsp[(3) - (3)].gen); + (yyval.addr2).from = (yyvsp[(1) - (3)].addr); + (yyval.addr2).to = (yyvsp[(3) - (3)].addr); } break; case 44: - -/* Line 1806 of yacc.c */ #line 191 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (5)].gen); - (yyval.gen2).from.scale = (yyvsp[(3) - (5)].lval); - (yyval.gen2).to = (yyvsp[(5) - (5)].gen); + (yyval.addr2).from = (yyvsp[(1) - (5)].addr); + (yyval.addr2).from.scale = (yyvsp[(3) - (5)].lval); + (yyval.addr2).to = (yyvsp[(5) - (5)].addr); } break; case 45: - -/* Line 1806 of yacc.c */ #line 199 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (3)].gen); - (yyval.gen2).to = (yyvsp[(3) - (3)].gen); + (yyval.addr2).from = (yyvsp[(1) - (3)].addr); + (yyval.addr2).to = (yyvsp[(3) - (3)].addr); } break; case 46: - -/* Line 1806 of yacc.c */ #line 204 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (5)].gen); - (yyval.gen2).from.scale = (yyvsp[(3) - (5)].lval); - (yyval.gen2).to = (yyvsp[(5) - (5)].gen); + (yyval.addr2).from = (yyvsp[(1) - (5)].addr); + (yyval.addr2).from.scale = (yyvsp[(3) - (5)].lval); + (yyval.addr2).to = (yyvsp[(5) - (5)].addr); } break; case 47: - -/* Line 1806 of yacc.c */ #line 212 "a.y" { - (yyval.gen2).from = nullgen; - (yyval.gen2).to = (yyvsp[(2) - (2)].gen); + (yyval.addr2).from = nullgen; + (yyval.addr2).to = (yyvsp[(2) - (2)].addr); } break; case 48: - -/* Line 1806 of yacc.c */ #line 217 "a.y" { - (yyval.gen2).from = nullgen; - (yyval.gen2).to = (yyvsp[(1) - (1)].gen); + (yyval.addr2).from = nullgen; + (yyval.addr2).to = (yyvsp[(1) - (1)].addr); } break; case 51: - -/* Line 1806 of yacc.c */ #line 228 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (3)].gen); - (yyval.gen2).to = (yyvsp[(3) - (3)].gen); + (yyval.addr2).from = (yyvsp[(1) - (3)].addr); + (yyval.addr2).to = (yyvsp[(3) - (3)].addr); } break; case 52: - -/* Line 1806 of yacc.c */ #line 233 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (5)].gen); - (yyval.gen2).to = (yyvsp[(3) - (5)].gen); - if((yyval.gen2).from.index != D_NONE) + (yyval.addr2).from = (yyvsp[(1) - (5)].addr); + (yyval.addr2).to = (yyvsp[(3) - (5)].addr); + if((yyval.addr2).from.index != D_NONE) yyerror("dp shift with lhs index"); - (yyval.gen2).from.index = (yyvsp[(5) - (5)].lval); + (yyval.addr2).from.index = (yyvsp[(5) - (5)].lval); } break; case 53: - -/* Line 1806 of yacc.c */ #line 243 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (3)].gen); - (yyval.gen2).to = (yyvsp[(3) - (3)].gen); + (yyval.addr2).from = (yyvsp[(1) - (3)].addr); + (yyval.addr2).to = (yyvsp[(3) - (3)].addr); } break; case 54: - -/* Line 1806 of yacc.c */ #line 248 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (5)].gen); - (yyval.gen2).to = (yyvsp[(3) - (5)].gen); - if((yyval.gen2).to.index != D_NONE) + (yyval.addr2).from = (yyvsp[(1) - (5)].addr); + (yyval.addr2).to = (yyvsp[(3) - (5)].addr); + if((yyval.addr2).to.index != D_NONE) yyerror("dp move with lhs index"); - (yyval.gen2).to.index = (yyvsp[(5) - (5)].lval); + (yyval.addr2).to.index = (yyvsp[(5) - (5)].lval); } break; case 55: - -/* Line 1806 of yacc.c */ #line 258 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (2)].gen); - (yyval.gen2).to = nullgen; + (yyval.addr2).from = (yyvsp[(1) - (2)].addr); + (yyval.addr2).to = nullgen; } break; case 56: - -/* Line 1806 of yacc.c */ #line 263 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (1)].gen); - (yyval.gen2).to = nullgen; + (yyval.addr2).from = (yyvsp[(1) - (1)].addr); + (yyval.addr2).to = nullgen; } break; case 57: - -/* Line 1806 of yacc.c */ #line 268 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (3)].gen); - (yyval.gen2).to = (yyvsp[(3) - (3)].gen); + (yyval.addr2).from = (yyvsp[(1) - (3)].addr); + (yyval.addr2).to = (yyvsp[(3) - (3)].addr); } break; case 58: - -/* Line 1806 of yacc.c */ #line 275 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (5)].gen); - (yyval.gen2).to = (yyvsp[(3) - (5)].gen); - (yyval.gen2).to.offset = (yyvsp[(5) - (5)].lval); + (yyval.addr2).from = (yyvsp[(1) - (5)].addr); + (yyval.addr2).to = (yyvsp[(3) - (5)].addr); + (yyval.addr2).to.offset = (yyvsp[(5) - (5)].lval); } break; case 59: - -/* Line 1806 of yacc.c */ #line 283 "a.y" { - (yyval.gen2).from = (yyvsp[(3) - (5)].gen); - (yyval.gen2).to = (yyvsp[(5) - (5)].gen); - if((yyvsp[(1) - (5)].gen).type != D_CONST) + (yyval.addr2).from = (yyvsp[(3) - (5)].addr); + (yyval.addr2).to = (yyvsp[(5) - (5)].addr); + if((yyvsp[(1) - (5)].addr).type != D_CONST) yyerror("illegal constant"); - (yyval.gen2).to.offset = (yyvsp[(1) - (5)].gen).offset; + (yyval.addr2).to.offset = (yyvsp[(1) - (5)].addr).offset; } break; case 60: - -/* Line 1806 of yacc.c */ #line 292 "a.y" { - (yyval.gen2).from = nullgen; - (yyval.gen2).to = nullgen; + (yyval.addr2).from = nullgen; + (yyval.addr2).to = nullgen; } break; case 61: - -/* Line 1806 of yacc.c */ #line 297 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (1)].gen); - (yyval.gen2).to = nullgen; + (yyval.addr2).from = (yyvsp[(1) - (1)].addr); + (yyval.addr2).to = nullgen; } break; case 62: - -/* Line 1806 of yacc.c */ #line 304 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (3)].gen); - (yyval.gen2).to = (yyvsp[(3) - (3)].gen); + (yyval.addr2).from = (yyvsp[(1) - (3)].addr); + (yyval.addr2).to = (yyvsp[(3) - (3)].addr); } break; case 63: - -/* Line 1806 of yacc.c */ #line 309 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (5)].gen); - (yyval.gen2).from.scale = (yyvsp[(3) - (5)].lval); - (yyval.gen2).to = (yyvsp[(5) - (5)].gen); + (yyval.addr2).from = (yyvsp[(1) - (5)].addr); + (yyval.addr2).from.scale = (yyvsp[(3) - (5)].lval); + (yyval.addr2).to = (yyvsp[(5) - (5)].addr); } break; case 64: - -/* Line 1806 of yacc.c */ #line 317 "a.y" { - if((yyvsp[(1) - (3)].gen).type != D_CONST || (yyvsp[(3) - (3)].gen).type != D_CONST) + if((yyvsp[(1) - (3)].addr).type != D_CONST || (yyvsp[(3) - (3)].addr).type != D_CONST) yyerror("arguments to PCDATA must be integer constants"); - (yyval.gen2).from = (yyvsp[(1) - (3)].gen); - (yyval.gen2).to = (yyvsp[(3) - (3)].gen); + (yyval.addr2).from = (yyvsp[(1) - (3)].addr); + (yyval.addr2).to = (yyvsp[(3) - (3)].addr); } break; case 65: - -/* Line 1806 of yacc.c */ #line 326 "a.y" { - if((yyvsp[(1) - (3)].gen).type != D_CONST) + if((yyvsp[(1) - (3)].addr).type != D_CONST) yyerror("index for FUNCDATA must be integer constant"); - if((yyvsp[(3) - (3)].gen).type != D_EXTERN && (yyvsp[(3) - (3)].gen).type != D_STATIC) + if((yyvsp[(3) - (3)].addr).type != D_EXTERN && (yyvsp[(3) - (3)].addr).type != D_STATIC) yyerror("value for FUNCDATA must be symbol reference"); - (yyval.gen2).from = (yyvsp[(1) - (3)].gen); - (yyval.gen2).to = (yyvsp[(3) - (3)].gen); + (yyval.addr2).from = (yyvsp[(1) - (3)].addr); + (yyval.addr2).to = (yyvsp[(3) - (3)].addr); } break; case 70: - -/* Line 1806 of yacc.c */ #line 343 "a.y" { - (yyval.gen) = (yyvsp[(2) - (2)].gen); + (yyval.addr) = (yyvsp[(2) - (2)].addr); } break; case 71: - -/* Line 1806 of yacc.c */ #line 347 "a.y" { - (yyval.gen) = (yyvsp[(2) - (2)].gen); + (yyval.addr) = (yyvsp[(2) - (2)].addr); } break; case 76: - -/* Line 1806 of yacc.c */ #line 359 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_BRANCH; - (yyval.gen).offset = (yyvsp[(1) - (4)].lval) + pc; + (yyval.addr) = nullgen; + (yyval.addr).type = D_BRANCH; + (yyval.addr).offset = (yyvsp[(1) - (4)].lval) + pc; } break; case 77: - -/* Line 1806 of yacc.c */ #line 365 "a.y" { - (yyval.gen) = nullgen; + (yyval.addr) = nullgen; if(pass == 2) yyerror("undefined label: %s", (yyvsp[(1) - (2)].sym)->name); - (yyval.gen).type = D_BRANCH; - (yyval.gen).sym = (yyvsp[(1) - (2)].sym); - (yyval.gen).offset = (yyvsp[(2) - (2)].lval); + (yyval.addr).type = D_BRANCH; + (yyval.addr).offset = (yyvsp[(2) - (2)].lval); } break; case 78: - -/* Line 1806 of yacc.c */ -#line 374 "a.y" +#line 373 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_BRANCH; - (yyval.gen).sym = (yyvsp[(1) - (2)].sym); - (yyval.gen).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_BRANCH; + (yyval.addr).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval); } break; case 79: - -/* Line 1806 of yacc.c */ -#line 383 "a.y" +#line 381 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = (yyvsp[(1) - (1)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = (yyvsp[(1) - (1)].lval); } break; case 80: - -/* Line 1806 of yacc.c */ -#line 388 "a.y" +#line 386 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = (yyvsp[(1) - (1)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = (yyvsp[(1) - (1)].lval); } break; case 81: - -/* Line 1806 of yacc.c */ -#line 393 "a.y" +#line 391 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = (yyvsp[(1) - (1)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = (yyvsp[(1) - (1)].lval); } break; case 82: - -/* Line 1806 of yacc.c */ -#line 398 "a.y" +#line 396 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = (yyvsp[(1) - (1)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = (yyvsp[(1) - (1)].lval); } break; case 83: - -/* Line 1806 of yacc.c */ -#line 403 "a.y" +#line 401 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_SP; + (yyval.addr) = nullgen; + (yyval.addr).type = D_SP; } break; case 84: - -/* Line 1806 of yacc.c */ -#line 408 "a.y" +#line 406 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = (yyvsp[(1) - (1)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = (yyvsp[(1) - (1)].lval); } break; case 85: - -/* Line 1806 of yacc.c */ -#line 413 "a.y" +#line 411 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = (yyvsp[(1) - (1)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = (yyvsp[(1) - (1)].lval); } break; case 86: - -/* Line 1806 of yacc.c */ -#line 419 "a.y" +#line 417 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_CONST; - (yyval.gen).offset = (yyvsp[(2) - (2)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_CONST; + (yyval.addr).offset = (yyvsp[(2) - (2)].lval); } break; case 87: - -/* Line 1806 of yacc.c */ -#line 427 "a.y" +#line 425 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_CONST; - (yyval.gen).offset = (yyvsp[(2) - (2)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_CONST; + (yyval.addr).offset = (yyvsp[(2) - (2)].lval); } break; case 88: - -/* Line 1806 of yacc.c */ -#line 433 "a.y" +#line 431 "a.y" { - (yyval.gen) = (yyvsp[(2) - (2)].gen); - (yyval.gen).index = (yyvsp[(2) - (2)].gen).type; - (yyval.gen).type = D_ADDR; + (yyval.addr) = (yyvsp[(2) - (2)].addr); + (yyval.addr).index = (yyvsp[(2) - (2)].addr).type; + (yyval.addr).type = D_ADDR; /* if($2.type == D_AUTO || $2.type == D_PARAM) yyerror("constant cannot be automatic: %s", @@ -2411,322 +2226,262 @@ yyreduce: break; case 89: - -/* Line 1806 of yacc.c */ -#line 444 "a.y" +#line 442 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_SCONST; - memcpy((yyval.gen).sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.gen).sval)); + (yyval.addr) = nullgen; + (yyval.addr).type = D_SCONST; + memcpy((yyval.addr).u.sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.addr).u.sval)); } break; case 90: - -/* Line 1806 of yacc.c */ -#line 450 "a.y" +#line 448 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_FCONST; - (yyval.gen).dval = (yyvsp[(2) - (2)].dval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_FCONST; + (yyval.addr).u.dval = (yyvsp[(2) - (2)].dval); } break; case 91: - -/* Line 1806 of yacc.c */ -#line 456 "a.y" +#line 454 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_FCONST; - (yyval.gen).dval = (yyvsp[(3) - (4)].dval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_FCONST; + (yyval.addr).u.dval = (yyvsp[(3) - (4)].dval); } break; case 92: - -/* Line 1806 of yacc.c */ -#line 462 "a.y" +#line 460 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_FCONST; - (yyval.gen).dval = -(yyvsp[(4) - (5)].dval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_FCONST; + (yyval.addr).u.dval = -(yyvsp[(4) - (5)].dval); } break; case 93: - -/* Line 1806 of yacc.c */ -#line 468 "a.y" +#line 466 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_FCONST; - (yyval.gen).dval = -(yyvsp[(3) - (3)].dval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_FCONST; + (yyval.addr).u.dval = -(yyvsp[(3) - (3)].dval); } break; case 96: - -/* Line 1806 of yacc.c */ -#line 480 "a.y" +#line 478 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_INDIR+D_NONE; - (yyval.gen).offset = (yyvsp[(1) - (1)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_INDIR+D_NONE; + (yyval.addr).offset = (yyvsp[(1) - (1)].lval); } break; case 97: - -/* Line 1806 of yacc.c */ -#line 486 "a.y" +#line 484 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_INDIR+(yyvsp[(3) - (4)].lval); - (yyval.gen).offset = (yyvsp[(1) - (4)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_INDIR+(yyvsp[(3) - (4)].lval); + (yyval.addr).offset = (yyvsp[(1) - (4)].lval); } break; case 98: - -/* Line 1806 of yacc.c */ -#line 492 "a.y" +#line 490 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_INDIR+D_SP; - (yyval.gen).offset = (yyvsp[(1) - (4)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_INDIR+D_SP; + (yyval.addr).offset = (yyvsp[(1) - (4)].lval); } break; case 99: - -/* Line 1806 of yacc.c */ -#line 498 "a.y" +#line 496 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_INDIR+(yyvsp[(3) - (4)].lval); - (yyval.gen).offset = (yyvsp[(1) - (4)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_INDIR+(yyvsp[(3) - (4)].lval); + (yyval.addr).offset = (yyvsp[(1) - (4)].lval); } break; case 100: - -/* Line 1806 of yacc.c */ -#line 504 "a.y" +#line 502 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_INDIR+D_NONE; - (yyval.gen).offset = (yyvsp[(1) - (6)].lval); - (yyval.gen).index = (yyvsp[(3) - (6)].lval); - (yyval.gen).scale = (yyvsp[(5) - (6)].lval); - checkscale((yyval.gen).scale); + (yyval.addr) = nullgen; + (yyval.addr).type = D_INDIR+D_NONE; + (yyval.addr).offset = (yyvsp[(1) - (6)].lval); + (yyval.addr).index = (yyvsp[(3) - (6)].lval); + (yyval.addr).scale = (yyvsp[(5) - (6)].lval); + checkscale((yyval.addr).scale); } break; case 101: - -/* Line 1806 of yacc.c */ -#line 513 "a.y" +#line 511 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_INDIR+(yyvsp[(3) - (9)].lval); - (yyval.gen).offset = (yyvsp[(1) - (9)].lval); - (yyval.gen).index = (yyvsp[(6) - (9)].lval); - (yyval.gen).scale = (yyvsp[(8) - (9)].lval); - checkscale((yyval.gen).scale); + (yyval.addr) = nullgen; + (yyval.addr).type = D_INDIR+(yyvsp[(3) - (9)].lval); + (yyval.addr).offset = (yyvsp[(1) - (9)].lval); + (yyval.addr).index = (yyvsp[(6) - (9)].lval); + (yyval.addr).scale = (yyvsp[(8) - (9)].lval); + checkscale((yyval.addr).scale); } break; case 102: - -/* Line 1806 of yacc.c */ -#line 522 "a.y" +#line 520 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_INDIR+(yyvsp[(3) - (9)].lval); - (yyval.gen).offset = (yyvsp[(1) - (9)].lval); - (yyval.gen).index = (yyvsp[(6) - (9)].lval); - (yyval.gen).scale = (yyvsp[(8) - (9)].lval); - checkscale((yyval.gen).scale); + (yyval.addr) = nullgen; + (yyval.addr).type = D_INDIR+(yyvsp[(3) - (9)].lval); + (yyval.addr).offset = (yyvsp[(1) - (9)].lval); + (yyval.addr).index = (yyvsp[(6) - (9)].lval); + (yyval.addr).scale = (yyvsp[(8) - (9)].lval); + checkscale((yyval.addr).scale); } break; case 103: - -/* Line 1806 of yacc.c */ -#line 531 "a.y" +#line 529 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_INDIR+(yyvsp[(2) - (3)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_INDIR+(yyvsp[(2) - (3)].lval); } break; case 104: - -/* Line 1806 of yacc.c */ -#line 536 "a.y" +#line 534 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_INDIR+D_SP; + (yyval.addr) = nullgen; + (yyval.addr).type = D_INDIR+D_SP; } break; case 105: - -/* Line 1806 of yacc.c */ -#line 541 "a.y" +#line 539 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_INDIR+D_NONE; - (yyval.gen).index = (yyvsp[(2) - (5)].lval); - (yyval.gen).scale = (yyvsp[(4) - (5)].lval); - checkscale((yyval.gen).scale); + (yyval.addr) = nullgen; + (yyval.addr).type = D_INDIR+D_NONE; + (yyval.addr).index = (yyvsp[(2) - (5)].lval); + (yyval.addr).scale = (yyvsp[(4) - (5)].lval); + checkscale((yyval.addr).scale); } break; case 106: - -/* Line 1806 of yacc.c */ -#line 549 "a.y" +#line 547 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_INDIR+(yyvsp[(2) - (8)].lval); - (yyval.gen).index = (yyvsp[(5) - (8)].lval); - (yyval.gen).scale = (yyvsp[(7) - (8)].lval); - checkscale((yyval.gen).scale); + (yyval.addr) = nullgen; + (yyval.addr).type = D_INDIR+(yyvsp[(2) - (8)].lval); + (yyval.addr).index = (yyvsp[(5) - (8)].lval); + (yyval.addr).scale = (yyvsp[(7) - (8)].lval); + checkscale((yyval.addr).scale); } break; case 107: - -/* Line 1806 of yacc.c */ -#line 559 "a.y" +#line 557 "a.y" { - (yyval.gen) = (yyvsp[(1) - (1)].gen); + (yyval.addr) = (yyvsp[(1) - (1)].addr); } break; case 108: - -/* Line 1806 of yacc.c */ -#line 563 "a.y" +#line 561 "a.y" { - (yyval.gen) = (yyvsp[(1) - (6)].gen); - (yyval.gen).index = (yyvsp[(3) - (6)].lval); - (yyval.gen).scale = (yyvsp[(5) - (6)].lval); - checkscale((yyval.gen).scale); + (yyval.addr) = (yyvsp[(1) - (6)].addr); + (yyval.addr).index = (yyvsp[(3) - (6)].lval); + (yyval.addr).scale = (yyvsp[(5) - (6)].lval); + checkscale((yyval.addr).scale); } break; case 109: - -/* Line 1806 of yacc.c */ -#line 572 "a.y" +#line 570 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = (yyvsp[(4) - (5)].lval); - (yyval.gen).sym = (yyvsp[(1) - (5)].sym); - (yyval.gen).offset = (yyvsp[(2) - (5)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = (yyvsp[(4) - (5)].lval); + (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (5)].sym)->name, 0); + (yyval.addr).offset = (yyvsp[(2) - (5)].lval); } break; case 110: - -/* Line 1806 of yacc.c */ -#line 579 "a.y" +#line 577 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_STATIC; - (yyval.gen).sym = (yyvsp[(1) - (7)].sym); - (yyval.gen).offset = (yyvsp[(4) - (7)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_STATIC; + (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (7)].sym)->name, 1); + (yyval.addr).offset = (yyvsp[(4) - (7)].lval); } break; case 111: - -/* Line 1806 of yacc.c */ -#line 587 "a.y" +#line 585 "a.y" { (yyval.lval) = 0; } break; case 112: - -/* Line 1806 of yacc.c */ -#line 591 "a.y" +#line 589 "a.y" { (yyval.lval) = (yyvsp[(2) - (2)].lval); } break; case 113: - -/* Line 1806 of yacc.c */ -#line 595 "a.y" +#line 593 "a.y" { (yyval.lval) = -(yyvsp[(2) - (2)].lval); } break; case 115: - -/* Line 1806 of yacc.c */ -#line 602 "a.y" +#line 600 "a.y" { (yyval.lval) = D_AUTO; } break; case 118: - -/* Line 1806 of yacc.c */ -#line 610 "a.y" +#line 608 "a.y" { (yyval.lval) = (yyvsp[(1) - (1)].sym)->value; } break; case 119: - -/* Line 1806 of yacc.c */ -#line 614 "a.y" +#line 612 "a.y" { (yyval.lval) = -(yyvsp[(2) - (2)].lval); } break; case 120: - -/* Line 1806 of yacc.c */ -#line 618 "a.y" +#line 616 "a.y" { (yyval.lval) = (yyvsp[(2) - (2)].lval); } break; case 121: - -/* Line 1806 of yacc.c */ -#line 622 "a.y" +#line 620 "a.y" { (yyval.lval) = ~(yyvsp[(2) - (2)].lval); } break; case 122: - -/* Line 1806 of yacc.c */ -#line 626 "a.y" +#line 624 "a.y" { (yyval.lval) = (yyvsp[(2) - (3)].lval); } break; case 123: - -/* Line 1806 of yacc.c */ -#line 632 "a.y" +#line 630 "a.y" { (yyval.lval) = ((yyvsp[(1) - (1)].lval) & 0xffffffffLL) + ((vlong)ArgsSizeUnknown << 32); @@ -2734,9 +2489,7 @@ yyreduce: break; case 124: - -/* Line 1806 of yacc.c */ -#line 637 "a.y" +#line 635 "a.y" { (yyval.lval) = (-(yyvsp[(2) - (2)].lval) & 0xffffffffLL) + ((vlong)ArgsSizeUnknown << 32); @@ -2744,9 +2497,7 @@ yyreduce: break; case 125: - -/* Line 1806 of yacc.c */ -#line 642 "a.y" +#line 640 "a.y" { (yyval.lval) = ((yyvsp[(1) - (3)].lval) & 0xffffffffLL) + (((yyvsp[(3) - (3)].lval) & 0xffffLL) << 32); @@ -2754,9 +2505,7 @@ yyreduce: break; case 126: - -/* Line 1806 of yacc.c */ -#line 647 "a.y" +#line 645 "a.y" { (yyval.lval) = (-(yyvsp[(2) - (4)].lval) & 0xffffffffLL) + (((yyvsp[(4) - (4)].lval) & 0xffffLL) << 32); @@ -2764,112 +2513,80 @@ yyreduce: break; case 128: - -/* Line 1806 of yacc.c */ -#line 655 "a.y" +#line 653 "a.y" { (yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval); } break; case 129: - -/* Line 1806 of yacc.c */ -#line 659 "a.y" +#line 657 "a.y" { (yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval); } break; case 130: - -/* Line 1806 of yacc.c */ -#line 663 "a.y" +#line 661 "a.y" { (yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval); } break; case 131: - -/* Line 1806 of yacc.c */ -#line 667 "a.y" +#line 665 "a.y" { (yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval); } break; case 132: - -/* Line 1806 of yacc.c */ -#line 671 "a.y" +#line 669 "a.y" { (yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval); } break; case 133: - -/* Line 1806 of yacc.c */ -#line 675 "a.y" +#line 673 "a.y" { (yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval); } break; case 134: - -/* Line 1806 of yacc.c */ -#line 679 "a.y" +#line 677 "a.y" { (yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval); } break; case 135: - -/* Line 1806 of yacc.c */ -#line 683 "a.y" +#line 681 "a.y" { (yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval); } break; case 136: - -/* Line 1806 of yacc.c */ -#line 687 "a.y" +#line 685 "a.y" { (yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval); } break; case 137: - -/* Line 1806 of yacc.c */ -#line 691 "a.y" +#line 689 "a.y" { (yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval); } break; - -/* Line 1806 of yacc.c */ -#line 2860 "y.tab.c" +/* Line 1267 of yacc.c. */ +#line 2588 "y.tab.c" default: break; } - /* User semantic actions sometimes alter yychar, and that requires - that yytoken be updated with the new translation. We take the - approach of translating immediately before every use of yytoken. - One alternative is translating here after every semantic action, - but that translation would be missed if the semantic action invokes - YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or - if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an - incorrect destructor might then be invoked immediately. In the - case of YYERROR or YYBACKUP, subsequent parser actions might lead - to an incorrect destructor call or verbose syntax error message - before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); YYPOPSTACK (yylen); @@ -2878,6 +2595,7 @@ yyreduce: *++yyvsp = yyval; + /* Now `shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ @@ -2897,10 +2615,6 @@ yyreduce: | yyerrlab -- here on detecting error | `------------------------------------*/ yyerrlab: - /* Make sure we have latest lookahead translation. See comments at - user semantic actions for why this is necessary. */ - yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); - /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { @@ -2908,36 +2622,37 @@ yyerrlab: #if ! YYERROR_VERBOSE yyerror (YY_("syntax error")); #else -# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ - yyssp, yytoken) { - char const *yymsgp = YY_("syntax error"); - int yysyntax_error_status; - yysyntax_error_status = YYSYNTAX_ERROR; - if (yysyntax_error_status == 0) - yymsgp = yymsg; - else if (yysyntax_error_status == 1) - { - if (yymsg != yymsgbuf) - YYSTACK_FREE (yymsg); - yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); - if (!yymsg) - { - yymsg = yymsgbuf; - yymsg_alloc = sizeof yymsgbuf; - yysyntax_error_status = 2; - } - else - { - yysyntax_error_status = YYSYNTAX_ERROR; - yymsgp = yymsg; - } - } - yyerror (yymsgp); - if (yysyntax_error_status == 2) - goto yyexhaustedlab; + YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); + if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) + { + YYSIZE_T yyalloc = 2 * yysize; + if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) + yyalloc = YYSTACK_ALLOC_MAXIMUM; + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yyalloc); + if (yymsg) + yymsg_alloc = yyalloc; + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + } + } + + if (0 < yysize && yysize <= yymsg_alloc) + { + (void) yysyntax_error (yymsg, yystate, yychar); + yyerror (yymsg); + } + else + { + yyerror (YY_("syntax error")); + if (yysize != 0) + goto yyexhaustedlab; + } } -# undef YYSYNTAX_ERROR #endif } @@ -2945,7 +2660,7 @@ yyerrlab: if (yyerrstatus == 3) { - /* If just tried and failed to reuse lookahead token after an + /* If just tried and failed to reuse look-ahead token after an error, discard it. */ if (yychar <= YYEOF) @@ -2962,7 +2677,7 @@ yyerrlab: } } - /* Else will try to reuse lookahead token after shifting the error + /* Else will try to reuse look-ahead token after shifting the error token. */ goto yyerrlab1; @@ -2996,7 +2711,7 @@ yyerrlab1: for (;;) { yyn = yypact[yystate]; - if (!yypact_value_is_default (yyn)) + if (yyn != YYPACT_NINF) { yyn += YYTERROR; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) @@ -3019,6 +2734,9 @@ yyerrlab1: YY_STACK_PRINT (yyss, yyssp); } + if (yyn == YYFINAL) + YYACCEPT; + *++yyvsp = yylval; @@ -3043,7 +2761,7 @@ yyabortlab: yyresult = 1; goto yyreturn; -#if !defined(yyoverflow) || YYERROR_VERBOSE +#ifndef yyoverflow /*-------------------------------------------------. | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ @@ -3054,14 +2772,9 @@ yyexhaustedlab: #endif yyreturn: - if (yychar != YYEMPTY) - { - /* Make sure we have latest lookahead translation. See comments at - user semantic actions for why this is necessary. */ - yytoken = YYTRANSLATE (yychar); - yydestruct ("Cleanup: discarding lookahead", - yytoken, &yylval); - } + if (yychar != YYEOF && yychar != YYEMPTY) + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); /* Do not reclaim the symbols of the rule which action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); diff --git a/src/cmd/6a/y.tab.h b/src/cmd/6a/y.tab.h index bba6081dc..e0eb5e12c 100644 --- a/src/cmd/6a/y.tab.h +++ b/src/cmd/6a/y.tab.h @@ -1,21 +1,24 @@ -/* A Bison parser, made by GNU Bison 2.5. */ +/* A Bison parser, made by GNU Bison 2.3. */ -/* Bison interface for Yacc-like parsers in C - - Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify +/* Skeleton interface for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - + the Free Software Foundation; either version 2, or (at your option) + any later version. + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License - along with this program. If not, see . */ + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work @@ -26,11 +29,10 @@ special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. - + This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ - /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE @@ -116,28 +118,22 @@ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE -{ - -/* Line 2068 of yacc.c */ #line 38 "a.y" - +{ Sym *sym; vlong lval; double dval; char sval[8]; - Gen gen; - Gen2 gen2; - - - -/* Line 2068 of yacc.c */ -#line 135 "y.tab.h" -} YYSTYPE; -# define YYSTYPE_IS_TRIVIAL 1 + Addr addr; + Addr2 addr2; +} +/* Line 1529 of yacc.c. */ +#line 132 "y.tab.h" + YYSTYPE; # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 #endif extern YYSTYPE yylval; - diff --git a/src/cmd/6c/gc.h b/src/cmd/6c/gc.h index c466a3afe..a196e55a8 100644 --- a/src/cmd/6c/gc.h +++ b/src/cmd/6c/gc.h @@ -46,11 +46,8 @@ #define SZ_DOUBLE 8 #define FNX 100 -typedef struct Adr Adr; -typedef struct Prog Prog; typedef struct Case Case; typedef struct C1 C1; -typedef struct Var Var; typedef struct Reg Reg; typedef struct Rgn Rgn; typedef struct Renv Renv; @@ -64,29 +61,9 @@ EXTERN struct short ptr; } idx; -struct Adr -{ - vlong offset; - double dval; - char sval[NSNAME]; - - Sym* sym; - uchar type; - uchar index; - uchar etype; - uchar scale; /* doubles as width in DATA op */ -}; -#define A ((Adr*)0) - #define INDEXED 9 -struct Prog -{ - Adr from; - Adr to; - Prog* link; - int32 lineno; - short as; -}; + +#define A ((Addr*)0) #define P ((Prog*)0) struct Case @@ -105,14 +82,6 @@ struct C1 int32 label; }; -struct Var -{ - vlong offset; - Sym* sym; - char name; - char etype; -}; - struct Reg { int32 pc; @@ -171,7 +140,6 @@ EXTERN Node vconstnode; EXTERN int32 continpc; EXTERN int32 curarg; EXTERN int32 cursafe; -EXTERN Prog* firstp; EXTERN Prog* lastp; EXTERN int32 maxargsafe; EXTERN int mnstring; @@ -226,7 +194,6 @@ EXTERN Reg* firstr; EXTERN Reg* lastr; EXTERN Reg zreg; EXTERN Reg* freer; -EXTERN Var var[NVAR]; EXTERN int32* idom; EXTERN Reg** rpo2r; EXTERN int32 maxnr; @@ -282,7 +249,7 @@ void regaalloc1(Node*, Node*); void regaalloc(Node*, Node*); void regind(Node*, Node*); void gprep(Node*, Node*); -void naddr(Node*, Adr*); +void naddr(Node*, Addr*); void gcmp(int, Node*, vlong); void gmove(Node*, Node*); void gins(int a, Node*, Node*); @@ -310,19 +277,11 @@ void nullwarn(Node*, Node*); void sextern(Sym*, Node*, int32, int32); void gextern(Sym*, Node*, int32, int32); void outcode(void); -void ieeedtod(Ieee*, double); /* * list */ void listinit(void); -int Pconv(Fmt*); -int Aconv(Fmt*); -int Dconv(Fmt*); -int Sconv(Fmt*); -int Rconv(Fmt*); -int Xconv(Fmt*); -int Bconv(Fmt*); /* * reg.c @@ -331,7 +290,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*, Addr*); void prop(Reg*, Bits, Bits); void loopit(Reg*, int32); void synch(Reg*, Bits); @@ -339,7 +298,7 @@ uint32 allreg(uint32, Rgn*); void paint1(Reg*, int); uint32 paint2(Reg*, int); void paint3(Reg*, int, int32, int); -void addreg(Adr*, int); +void addreg(Addr*, int); /* * peep.c @@ -348,17 +307,17 @@ void peep(void); void excise(Reg*); Reg* uniqp(Reg*); Reg* uniqs(Reg*); -int regtyp(Adr*); -int anyvar(Adr*); +int regtyp(Addr*); +int anyvar(Addr*); int subprop(Reg*); int copyprop(Reg*); -int copy1(Adr*, Adr*, Reg*, int); -int copyu(Prog*, Adr*, Adr*); +int copy1(Addr*, Addr*, Reg*, int); +int copyu(Prog*, Addr*, Addr*); -int copyas(Adr*, Adr*); -int copyau(Adr*, Adr*); -int copysub(Adr*, Adr*, Adr*, int); -int copysub1(Prog*, Adr*, Adr*, int); +int copyas(Addr*, Addr*); +int copyau(Addr*, Addr*); +int copysub(Addr*, Addr*, Addr*, int); +int copysub1(Prog*, Addr*, Addr*, int); int32 RtoB(int); int32 FtoB(int); @@ -396,14 +355,6 @@ void mulgen(Type*, Node*, Node*); void genmuladd(Node*, Node*, int, Node*); void shiftit(Type*, Node*, Node*); -#pragma varargck type "A" int -#pragma varargck type "B" Bits -#pragma varargck type "D" Adr* -#pragma varargck type "lD" Adr* -#pragma varargck type "P" Prog* -#pragma varargck type "R" int -#pragma varargck type "S" char* - #define D_X7 (D_X0+7) void fgopcode(int, Node*, Node*, int, int); diff --git a/src/cmd/6c/list.c b/src/cmd/6c/list.c index b5a60ac9a..28f5b8df7 100644 --- a/src/cmd/6c/list.c +++ b/src/cmd/6c/list.c @@ -34,358 +34,5 @@ void listinit(void) { - - fmtinstall('A', Aconv); - fmtinstall('B', Bconv); - fmtinstall('P', Pconv); - fmtinstall('S', Sconv); - fmtinstall('D', Dconv); - fmtinstall('R', Rconv); -} - -int -Bconv(Fmt *fp) -{ - char str[STRINGSZ], ss[STRINGSZ], *s; - Bits bits; - int i; - - str[0] = 0; - bits = va_arg(fp->args, Bits); - while(bany(&bits)) { - i = bnum(bits); - if(str[0]) - strcat(str, " "); - if(var[i].sym == S) { - sprint(ss, "$%lld", var[i].offset); - s = ss; - } else - s = var[i].sym->name; - if(strlen(str) + strlen(s) + 1 >= STRINGSZ) - break; - strcat(str, s); - bits.b[i/32] &= ~(1L << (i%32)); - } - return fmtstrcpy(fp, str); -} - -int -Pconv(Fmt *fp) -{ - char str[STRINGSZ]; - Prog *p; - - p = va_arg(fp->args, Prog*); - 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,%D", - p->lineno, p->as, &p->from, &p->to); - break; - } - return fmtstrcpy(fp, str); -} - -int -Aconv(Fmt *fp) -{ - int i; - - i = va_arg(fp->args, int); - return fmtstrcpy(fp, anames[i]); -} - -int -Dconv(Fmt *fp) -{ - char str[STRINGSZ], s[STRINGSZ]; - Adr *a; - int i; - - a = va_arg(fp->args, Adr*); - i = a->type; - - if(fp->flags & FmtLong) { - if(i == D_CONST) - sprint(str, "$%lld-%lld", a->offset&0xffffffffLL, a->offset>>32); - else { - // ATEXT dst is not constant - sprint(str, "!!%D", a); - } - goto brk; - } - - if(i >= D_INDIR) { - if(a->offset) - sprint(str, "%lld(%R)", a->offset, i-D_INDIR); - else - sprint(str, "(%R)", i-D_INDIR); - goto brk; - } - switch(i) { - default: - if(a->offset) - sprint(str, "$%lld,%R", a->offset, i); - else - sprint(str, "%R", i); - break; - - case D_NONE: - str[0] = 0; - break; - - case D_BRANCH: - sprint(str, "%lld", a->offset); - break; - - case D_EXTERN: - sprint(str, "%s+%lld(SB)", a->sym->name, a->offset); - break; - - case D_STATIC: - sprint(str, "%s<>+%lld(SB)", a->sym->name, a->offset); - break; - - case D_AUTO: - if(a->sym) - sprint(str, "%s+%lld(SP)", a->sym->name, a->offset); - else - sprint(str, "%lld(SP)", a->offset); - break; - - case D_PARAM: - if(a->sym) - sprint(str, "%s+%lld(FP)", a->sym->name, a->offset); - else - sprint(str, "%lld(FP)", a->offset); - break; - - case D_CONST: - sprint(str, "$%lld", a->offset); - break; - - case D_FCONST: - sprint(str, "$(%.17e)", a->dval); - break; - - case D_SCONST: - sprint(str, "$\"%S\"", a->sval); - break; - - case D_ADDR: - a->type = a->index; - a->index = D_NONE; - sprint(str, "$%D", a); - a->index = a->type; - a->type = D_ADDR; - goto conv; - } -brk: - if(a->index != D_NONE) { - sprint(s, "(%R*%d)", (int)a->index, (int)a->scale); - strcat(str, s); - } -conv: - return fmtstrcpy(fp, str); -} - -char* regstr[] = -{ - "AL", /* [D_AL] */ - "CL", - "DL", - "BL", - "SPB", - "BPB", - "SIB", - "DIB", - "R8B", - "R9B", - "R10B", - "R11B", - "R12B", - "R13B", - "R14B", - "R15B", - - "AX", /* [D_AX] */ - "CX", - "DX", - "BX", - "SP", - "BP", - "SI", - "DI", - "R8", - "R9", - "R10", - "R11", - "R12", - "R13", - "R14", - "R15", - - "AH", - "CH", - "DH", - "BH", - - "F0", /* [D_F0] */ - "F1", - "F2", - "F3", - "F4", - "F5", - "F6", - "F7", - - "M0", - "M1", - "M2", - "M3", - "M4", - "M5", - "M6", - "M7", - - "X0", - "X1", - "X2", - "X3", - "X4", - "X5", - "X6", - "X7", - "X8", - "X9", - "X10", - "X11", - "X12", - "X13", - "X14", - "X15", - - "CS", /* [D_CS] */ - "SS", - "DS", - "ES", - "FS", - "GS", - - "GDTR", /* [D_GDTR] */ - "IDTR", /* [D_IDTR] */ - "LDTR", /* [D_LDTR] */ - "MSW", /* [D_MSW] */ - "TASK", /* [D_TASK] */ - - "CR0", /* [D_CR] */ - "CR1", - "CR2", - "CR3", - "CR4", - "CR5", - "CR6", - "CR7", - "CR8", - "CR9", - "CR10", - "CR11", - "CR12", - "CR13", - "CR14", - "CR15", - - "DR0", /* [D_DR] */ - "DR1", - "DR2", - "DR3", - "DR4", - "DR5", - "DR6", - "DR7", - - "TR0", /* [D_TR] */ - "TR1", - "TR2", - "TR3", - "TR4", - "TR5", - "TR6", - "TR7", - - "NONE", /* [D_NONE] */ -}; - -int -Rconv(Fmt *fp) -{ - char str[STRINGSZ]; - int r; - - r = va_arg(fp->args, int); - if(r >= D_AL && r <= D_NONE) - sprint(str, "%s", regstr[r-D_AL]); - else - sprint(str, "gok(%d)", r); - - return fmtstrcpy(fp, str); -} - -int -Sconv(Fmt *fp) -{ - int i, c; - char str[STRINGSZ], *p, *a; - - a = va_arg(fp->args, char*); - p = str; - for(i=0; i= 'a' && c <= 'z' || - c >= 'A' && c <= 'Z' || - c >= '0' && c <= '9') { - *p++ = c; - continue; - } - *p++ = '\\'; - switch(c) { - default: - if(c < 040 || c >= 0177) - break; /* not portable */ - p[-1] = c; - continue; - case 0: - *p++ = 'z'; - continue; - case '\\': - case '"': - *p++ = c; - continue; - case '\n': - *p++ = 'n'; - continue; - case '\t': - *p++ = 't'; - continue; - } - *p++ = (c>>6) + '0'; - *p++ = ((c>>3) & 7) + '0'; - *p++ = (c & 7) + '0'; - } - *p = 0; - return fmtstrcpy(fp, str); + listinit6(); } diff --git a/src/cmd/6c/peep.c b/src/cmd/6c/peep.c index 0a3bd84bc..a11067c84 100644 --- a/src/cmd/6c/peep.c +++ b/src/cmd/6c/peep.c @@ -276,7 +276,7 @@ uniqs(Reg *r) } int -regtyp(Adr *a) +regtyp(Addr *a) { int t; @@ -306,7 +306,7 @@ int subprop(Reg *r0) { Prog *p; - Adr *v1, *v2; + Addr *v1, *v2; Reg *r; int t; @@ -445,7 +445,7 @@ int copyprop(Reg *r0) { Prog *p; - Adr *v1, *v2; + Addr *v1, *v2; Reg *r; p = r0->prog; @@ -459,7 +459,7 @@ copyprop(Reg *r0) } int -copy1(Adr *v1, Adr *v2, Reg *r, int f) +copy1(Addr *v1, Addr *v2, Reg *r, int f) { int t; Prog *p; @@ -544,7 +544,7 @@ copy1(Adr *v1, Adr *v2, Reg *r, int f) * 0 otherwise (not touched) */ int -copyu(Prog *p, Adr *v, Adr *s) +copyu(Prog *p, Addr *v, Addr *s) { switch(p->as) { @@ -835,7 +835,7 @@ copyu(Prog *p, Adr *v, Adr *s) * semantics */ int -copyas(Adr *a, Adr *v) +copyas(Addr *a, Addr *v) { if(a->type != v->type) return 0; @@ -851,7 +851,7 @@ copyas(Adr *a, Adr *v) * either direct or indirect */ int -copyau(Adr *a, Adr *v) +copyau(Addr *a, Addr *v) { if(copyas(a, v)) @@ -870,7 +870,7 @@ copyau(Adr *a, Adr *v) * return failure to substitute */ int -copysub(Adr *a, Adr *v, Adr *s, int f) +copysub(Addr *a, Addr *v, Addr *s, int f) { int t; diff --git a/src/cmd/6c/reg.c b/src/cmd/6c/reg.c index edd93a0a0..348d747b7 100644 --- a/src/cmd/6c/reg.c +++ b/src/cmd/6c/reg.c @@ -663,8 +663,10 @@ brk: r1 = 0; /* set */ for(r = firstr; r != R; r = r->link) { p = r->prog; - if(p->to.type == D_BRANCH) + if(p->to.type == D_BRANCH) { p->to.offset = r->s2->pc; + p->to.u.branch = r->s2->prog; + } r1 = r; } @@ -691,7 +693,7 @@ void addmove(Reg *r, int bn, int rn, int f) { Prog *p, *p1; - Adr *a; + Addr *a; Var *v; p1 = alloc(sizeof(*p1)); @@ -715,7 +717,7 @@ addmove(Reg *r, int bn, int rn, int f) p1->as = AMOVB; if(v->etype == TSHORT || v->etype == TUSHORT) p1->as = AMOVW; - if(v->etype == TVLONG || v->etype == TUVLONG || v->etype == TIND) + if(v->etype == TVLONG || v->etype == TUVLONG || (v->etype == TIND && ewidth[TIND] == 8)) p1->as = AMOVQ; if(v->etype == TFLOAT) p1->as = AMOVSS; @@ -759,13 +761,13 @@ doregbits(int r) } Bits -mkvar(Reg *r, Adr *a) +mkvar(Reg *r, Addr *a) { Var *v; int i, t, n, et, z; int32 o; Bits bit; - Sym *s; + LSym *s; /* * mark registers used @@ -792,7 +794,7 @@ mkvar(Reg *r, Adr *a) break; } s = a->sym; - if(s == S) + if(s == nil) goto none; if(s->name[0] == '.') goto none; @@ -1181,7 +1183,7 @@ uint32 regset(Reg *r, uint32 bb) { uint32 b, set; - Adr v; + Addr v; int c; set = 0; @@ -1202,7 +1204,7 @@ uint32 reguse(Reg *r, uint32 bb) { uint32 b, set; - Adr v; + Addr v; int c; set = 0; @@ -1349,7 +1351,7 @@ paint3(Reg *r, int bn, int32 rb, int rn) } void -addreg(Adr *a, int rn) +addreg(Addr *a, int rn) { a->sym = 0; @@ -1371,6 +1373,8 @@ BtoR(int32 b) { b &= 0xffffL; + if(nacl) + b &= ~((1<<(D_BP-D_AX)) | (1<<(D_R15-D_AX))); if(b == 0) return 0; return bitno(b) + D_AX; @@ -1459,10 +1463,11 @@ fixjmp(Reg *firstr) for(r=firstr; r; r=r->link) { p = r->prog; if(debug['R'] && debug['v']) - print("%04d %P\n", r->pc, p); + print("%04d %P\n", (int)r->pc, p); if(p->as != ACALL && p->to.type == D_BRANCH && r->s2 && r->s2->prog->as == AJMP) { r->s2 = chasejmp(r->s2, &jmploop); p->to.offset = r->s2->pc; + p->to.u.branch = r->s2->prog; if(debug['R'] && debug['v']) print("->%P\n", p); } @@ -1483,7 +1488,7 @@ fixjmp(Reg *firstr) // Let it stay. } else { if(debug['R'] && debug['v']) - print("del %04d %P\n", r->pc, p); + print("del %04d %P\n", (int)r->pc, p); p->as = ANOP; } } @@ -1496,7 +1501,7 @@ fixjmp(Reg *firstr) p = r->prog; if(p->as == AJMP && p->to.type == D_BRANCH && r->s2 == r->link) { if(debug['R'] && debug['v']) - print("del %04d %P\n", r->pc, p); + print("del %04d %P\n", (int)r->pc, p); p->as = ANOP; } } @@ -1517,7 +1522,7 @@ fixjmp(Reg *firstr) if(debug['R'] && debug['v']) { print("\n"); for(r=firstr; r; r=r->link) - print("%04d %P\n", r->pc, r->prog); + print("%04d %P\n", (int)r->pc, r->prog); print("\n"); } } diff --git a/src/cmd/6c/sgen.c b/src/cmd/6c/sgen.c index 744a60222..ba1c1f652 100644 --- a/src/cmd/6c/sgen.c +++ b/src/cmd/6c/sgen.c @@ -207,7 +207,7 @@ xcom(Node *n) n->addable = 8; break; } - if(n->addable == 8 && !side(n)) { + if(n->addable == 8 && !side(n) && !nacl) { indx(n); l = new1(OINDEX, idx.basetree, idx.regtree); l->scale = idx.scale; diff --git a/src/cmd/6c/swt.c b/src/cmd/6c/swt.c index 2496da477..d7713648d 100644 --- a/src/cmd/6c/swt.c +++ b/src/cmd/6c/swt.c @@ -164,7 +164,7 @@ outstring(char *s, int32 n) p->from.offset += nstring - NSNAME; p->from.scale = NSNAME; p->to.type = D_SCONST; - memmove(p->to.sval, string, NSNAME); + memmove(p->to.u.sval, string, NSNAME); mnstring = 0; } n--; @@ -185,7 +185,7 @@ sextern(Sym *s, Node *a, int32 o, int32 w) p->from.offset += o+e; p->from.scale = lw; p->to.type = D_SCONST; - memmove(p->to.sval, a->cstring+e, lw); + memmove(p->to.u.sval, a->cstring+e, lw); } } @@ -215,30 +215,12 @@ gextern(Sym *s, Node *a, int32 o, int32 w) } } -void zname(Biobuf*, Sym*, int); -void zaddr(Biobuf*, Adr*, int); -void outhist(Biobuf*); - void outcode(void) { - struct { Sym *sym; short type; } h[NSYM]; - Prog *p; - Sym *s; - int f, sf, st, t, sym; + int f; Biobuf b; - if(debug['S']) { - for(p = firstp; p != P; p = p->link) - if(p->as != ADATA && p->as != AGLOBL) - pc--; - for(p = firstp; p != P; p = p->link) { - print("%P\n", p); - if(p->as != ADATA && p->as != AGLOBL) - pc++; - } - } - f = open(outfile, OWRITE); if(f < 0) { diag(Z, "cannot open %s", outfile); @@ -246,7 +228,7 @@ outcode(void) } Binit(&b, f, OWRITE); - Bprint(&b, "go object %s %s %s\n", getgoos(), thestring, getgoversion()); + Bprint(&b, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion()); if(pragcgobuf.to > pragcgobuf.start) { Bprint(&b, "\n"); Bprint(&b, "$$ // exports\n\n"); @@ -257,261 +239,12 @@ outcode(void) } Bprint(&b, "!\n"); - outhist(&b); - for(sym=0; symlink) { - jackpot: - sf = 0; - s = p->from.sym; - while(s != S) { - sf = s->sym; - if(sf < 0 || sf >= NSYM) - sf = 0; - t = p->from.type; - if(t == D_ADDR) - t = p->from.index; - if(h[sf].type == t) - if(h[sf].sym == s) - break; - s->sym = sym; - zname(&b, s, t); - h[sym].sym = s; - h[sym].type = t; - sf = sym; - sym++; - if(sym >= NSYM) - sym = 1; - break; - } - st = 0; - s = p->to.sym; - while(s != S) { - st = s->sym; - if(st < 0 || st >= NSYM) - st = 0; - t = p->to.type; - if(t == D_ADDR) - t = p->to.index; - if(h[st].type == t) - if(h[st].sym == s) - break; - s->sym = sym; - zname(&b, s, t); - h[sym].sym = s; - h[sym].type = t; - st = sym; - sym++; - if(sym >= NSYM) - sym = 1; - if(st == sf) - goto jackpot; - break; - } - BPUTLE2(&b, p->as); - BPUTLE4(&b, p->lineno); - zaddr(&b, &p->from, sf); - zaddr(&b, &p->to, st); - } + writeobj(ctxt, &b); Bterm(&b); close(f); - firstp = P; lastp = P; } -void -outhist(Biobuf *b) -{ - Hist *h; - char *p, *q, *op, c; - Prog pg; - int n; - char *tofree; - static int first = 1; - static char *goroot, *goroot_final; - - if(first) { - // Decide whether we need to rewrite paths from $GOROOT to $GOROOT_FINAL. - first = 0; - goroot = getenv("GOROOT"); - goroot_final = getenv("GOROOT_FINAL"); - if(goroot == nil) - goroot = ""; - if(goroot_final == nil) - goroot_final = goroot; - if(strcmp(goroot, goroot_final) == 0) { - goroot = nil; - goroot_final = nil; - } - } - - tofree = nil; - pg = zprog; - pg.as = AHISTORY; - c = pathchar(); - for(h = hist; h != H; h = h->link) { - p = h->name; - if(p != nil && goroot != nil) { - n = strlen(goroot); - if(strncmp(p, goroot, strlen(goroot)) == 0 && p[n] == '/') { - tofree = smprint("%s%s", goroot_final, p+n); - p = tofree; - } - } - op = 0; - if(systemtype(Windows) && p && p[1] == ':'){ - c = p[2]; - } else if(p && p[0] != c && h->offset == 0 && pathname){ - if(systemtype(Windows) && pathname[1] == ':') { - op = p; - p = pathname; - c = p[2]; - } else if(pathname[0] == c){ - op = p; - p = pathname; - } - } - while(p) { - q = utfrune(p, c); - if(q) { - n = q-p; - if(n == 0){ - n = 1; /* leading "/" */ - *p = '/'; /* don't emit "\" on windows */ - } - q++; - } else { - n = strlen(p); - q = 0; - } - if(n) { - BPUTLE2(b, ANAME); - BPUTC(b, D_FILE); - BPUTC(b, 1); - BPUTC(b, '<'); - Bwrite(b, p, n); - BPUTC(b, 0); - } - p = q; - if(p == 0 && op) { - p = op; - op = 0; - } - } - pg.lineno = h->line; - pg.to.type = zprog.to.type; - pg.to.offset = h->offset; - if(h->offset) - pg.to.type = D_CONST; - - BPUTLE2(b, pg.as); - BPUTLE4(b, pg.lineno); - zaddr(b, &pg.from, 0); - zaddr(b, &pg.to, 0); - - if(tofree) { - free(tofree); - tofree = nil; - } - } -} - -void -zname(Biobuf *b, Sym *s, int t) -{ - char *n; - uint32 sig; - - if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){ - sig = sign(s); - BPUTLE2(b, ASIGNAME); - BPUTLE4(b, sig); - s->sig = SIGDONE; - } - else{ - BPUTLE2(b, ANAME); /* as */ - } - BPUTC(b, t); /* type */ - BPUTC(b, s->sym); /* sym */ - n = s->name; - while(*n) { - BPUTC(b, *n); - n++; - } - BPUTC(b, 0); -} - -void -zaddr(Biobuf *b, Adr *a, int s) -{ - int32 l; - int i, t; - char *n; - Ieee e; - - t = 0; - if(a->index != D_NONE || a->scale != 0) - t |= T_INDEX; - if(s != 0) - t |= T_SYM; - - switch(a->type) { - default: - t |= T_TYPE; - case D_NONE: - if(a->offset != 0) { - t |= T_OFFSET; - l = a->offset; - if((vlong)l != a->offset) - t |= T_64; - } - break; - case D_FCONST: - t |= T_FCONST; - break; - case D_SCONST: - t |= T_SCONST; - break; - } - BPUTC(b, t); - - if(t & T_INDEX) { /* implies index, scale */ - BPUTC(b, a->index); - BPUTC(b, a->scale); - } - if(t & T_OFFSET) { /* implies offset */ - l = a->offset; - BPUTLE4(b, l); - if(t & T_64) { - l = a->offset>>32; - BPUTLE4(b, l); - } - } - if(t & T_SYM) /* implies sym */ - BPUTC(b, s); - if(t & T_FCONST) { - ieeedtod(&e, a->dval); - l = e.l; - BPUTLE4(b, l); - l = e.h; - BPUTLE4(b, l); - return; - } - if(t & T_SCONST) { - n = a->sval; - for(i=0; itype); -} - int32 align(int32 i, Type *t, int op, int32 *maxalign) { @@ -559,6 +292,21 @@ align(int32 i, Type *t, int op, int32 *maxalign) break; case Aarg1: /* initial align of parameter */ + if(ewidth[TIND] == 4) { + if(typesu[t->etype]) { + for(v = t->link; v != T; v = v->down) + o = align(o, v, Aarg1, maxalign); + goto out; + } + w = ewidth[t->etype]; + if(typev[t->etype] || t->etype == TDOUBLE) + w = 8; + else if(w <= 0 || w >= 4) + w = 4; + else + w = 1; + break; + } w = ewidth[t->etype]; if(w <= 0 || w >= SZ_VLONG) { w = SZ_VLONG; @@ -569,6 +317,10 @@ align(int32 i, Type *t, int op, int32 *maxalign) case Aarg2: /* width of a parameter */ o += t->width; + if(ewidth[TIND] == 4) { + o = align(o, t, Aarg1, maxalign); + goto out; + } w = t->width; if(w > SZ_VLONG) w = SZ_VLONG; @@ -582,6 +334,7 @@ align(int32 i, Type *t, int op, int32 *maxalign) o = xround(o, w); if(maxalign && *maxalign < w) *maxalign = w; +out: if(debug['A']) 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 6f5d42da5..4d07436c3 100644 --- a/src/cmd/6c/txt.c +++ b/src/cmd/6c/txt.c @@ -30,15 +30,27 @@ #include "gc.h" +int thechar = '6'; +char *thestring = "amd64"; + +LinkArch *thelinkarch = &linkamd64; + +void +linkarchinit(void) +{ + if(strcmp(getgoarch(), "amd64p32") == 0) + thelinkarch = &linkamd64p32; +} + void ginit(void) { int i; Type *t; - thechar = '6'; - thestring = "amd64"; - dodefine("_64BIT"); + dodefine("_64BITREG"); + if(ewidth[TIND] == 8) + dodefine("_64BIT"); listinit(); nstring = 0; mnstring = 0; @@ -47,7 +59,6 @@ ginit(void) breakpc = -1; continpc = -1; cases = C; - firstp = P; lastp = P; tfield = types[TINT]; @@ -129,6 +140,10 @@ ginit(void) if(i >= D_X0 && i <= D_X7) reg[i] = 0; } + if(nacl) { + reg[D_BP] = 1; + reg[D_R15] = 1; + } } void @@ -138,6 +153,10 @@ gclean(void) Sym *s; reg[D_SP]--; + if(nacl) { + reg[D_BP]--; + reg[D_R15]--; + } for(i=D_AX; i<=D_R15; i++) if(reg[i]) diag(Z, "reg %R left allocated", i); @@ -168,17 +187,18 @@ gclean(void) void nextpc(void) { + Plist *pl; p = alloc(sizeof(*p)); *p = zprog; p->lineno = nearln; + p->pc = pc; pc++; - if(firstp == P) { - firstp = p; - lastp = p; - return; - } - lastp->link = p; + if(lastp == nil) { + pl = linknewplist(ctxt); + pl->firstpc = p; + } else + lastp->link = p; lastp = p; } @@ -441,7 +461,7 @@ regaalloc1(Node *n, Node *nn) return; } nodreg(n, nn, REGARG); - reg[REGARG]++; + reg[(uchar)REGARG]++; curarg = align(curarg, nn->type, Aarg1, nil); curarg = align(curarg, nn->type, Aarg2, nil); maxargsafe = maxround(maxargsafe, cursafe+curarg); @@ -474,7 +494,7 @@ regind(Node *n, Node *nn) } void -naddr(Node *n, Adr *a) +naddr(Node *n, Addr *a) { int32 v; @@ -489,11 +509,11 @@ naddr(Node *n, Adr *a) case OREGISTER: a->type = n->reg; - a->sym = S; + a->sym = nil; break; case OEXREG: - a->type = D_INDIR + D_GS; + a->type = D_INDIR + D_TLS; a->offset = n->reg - 1; break; @@ -534,14 +554,14 @@ naddr(Node *n, Adr *a) case OINDREG: a->type = n->reg+D_INDIR; - a->sym = S; + a->sym = nil; a->offset = n->xoffset; break; case ONAME: a->etype = n->etype; a->type = D_STATIC; - a->sym = n->sym; + a->sym = linksym(n->sym); a->offset = n->xoffset; if(n->class == CSTATIC) break; @@ -562,12 +582,12 @@ naddr(Node *n, Adr *a) case OCONST: if(typefd[n->type->etype]) { a->type = D_FCONST; - a->dval = n->fconst; + a->u.dval = n->fconst; break; } - a->sym = S; + a->sym = nil; a->type = D_CONST; - if(typev[n->type->etype] || n->type->etype == TIND) + if(typev[n->type->etype] || (n->type->etype == TIND && ewidth[TIND] == 8)) a->offset = n->vconst; else a->offset = convvtox(n->vconst, typeu[n->type->etype]? TULONG: TLONG); @@ -630,6 +650,12 @@ gmove(Node *f, Node *t) ft = f->type->etype; tt = t->type->etype; + if(ewidth[TIND] == 4) { + if(ft == TIND) + ft = TUINT; + if(tt == TIND) + tt = TUINT; + } t64 = tt == TVLONG || tt == TUVLONG || tt == TIND; if(debug['M']) print("gop: %O %O[%s],%O[%s]\n", OAS, @@ -721,6 +747,8 @@ gmove(Node *f, Node *t) goto ld; case TIND: a = AMOVQ; + if(ewidth[TIND] == 4) + a = AMOVL; ld: regalloc(&nod, f, t); @@ -1226,6 +1254,8 @@ gopcode(int o, Type *ty, Node *f, Node *t) et = TLONG; if(ty != T) et = ty->etype; + if(et == TIND && ewidth[TIND] == 4) + et = TUINT; if(debug['M']) { if(f != Z && f->type != T) print("gop: %O %O[%s],", o, f->op, tnames[et]); @@ -1487,9 +1517,10 @@ gbranch(int o) void patch(Prog *op, int32 pc) { - op->to.offset = pc; op->to.type = D_BRANCH; + op->to.u.branch = nil; + op->pcond = nil; } void @@ -1499,7 +1530,7 @@ gpseudo(int a, Sym *s, Node *n) nextpc(); p->as = a; p->from.type = D_EXTERN; - p->from.sym = s; + p->from.sym = linksym(s); switch(a) { case ATEXT: @@ -1561,7 +1592,7 @@ exreg(Type *t) if(exregoffset >= 64) return 0; o = exregoffset; - exregoffset += 8; + exregoffset += ewidth[TIND]; return o+1; // +1 to avoid 0 == failure; naddr's case OEXREG will subtract 1. } return 0; diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c index ada2baa81..4dd505b08 100644 --- a/src/cmd/6g/cgen.c +++ b/src/cmd/6g/cgen.c @@ -247,6 +247,7 @@ cgen(Node *n, Node *res) case OOR: case OXOR: case OADD: + case OADDPTR: case OMUL: a = optoas(n->op, nl->type); if(a == AIMULB) { @@ -813,6 +814,7 @@ agen(Node *n, Node *res) // The generated code is just going to panic, so it need not // be terribly efficient. See issue 3670. tempname(&n1, n->type); + gvardef(&n1); clearfat(&n1); regalloc(&n2, types[tptr], res); gins(ALEAQ, &n1, &n2); @@ -1060,6 +1062,12 @@ bgen(Node *n, int true, int likely, Prog *to) } nr = N; + while(n->op == OCONVNOP) { + n = n->left; + if(n->ninit != nil) + genlist(n->ninit); + } + switch(n->op) { default: def: @@ -1337,6 +1345,8 @@ sgen(Node *n, Node *ns, int64 w) { Node nodl, nodr, nodsi, noddi, cx, oldcx, tmp; vlong c, q, odst, osrc; + NodeList *l; + Prog *p; if(debug['g']) { print("\nsgen w=%lld\n", w); @@ -1349,6 +1359,13 @@ sgen(Node *n, Node *ns, int64 w) if(w < 0) fatal("sgen copy %lld", w); + + // If copying .args, that's all the results, so record definition sites + // for them for the liveness analysis. + if(ns->op == ONAME && strcmp(ns->sym->name, ".args") == 0) + for(l = curfn->dcl; l != nil; l = l->next) + if(l->n->class == PPARAMOUT) + gvardef(l->n); // Avoid taking the address for simple enough types. if(componentgen(n, ns)) @@ -1380,11 +1397,16 @@ sgen(Node *n, Node *ns, int64 w) if(n->ullman >= ns->ullman) { agenr(n, &nodr, N); + if(ns->op == ONAME) + gvardef(ns); agenr(ns, &nodl, N); } else { + if(ns->op == ONAME) + gvardef(ns); agenr(ns, &nodl, N); agenr(n, &nodr, N); } + nodreg(&noddi, types[tptr], D_DI); nodreg(&nodsi, types[tptr], D_SI); gmove(&nodl, &noddi); @@ -1403,23 +1425,23 @@ sgen(Node *n, Node *ns, int64 w) // reverse direction gins(ASTD, N, N); // set direction flag if(c > 0) { - gconreg(AADDQ, w-1, D_SI); - gconreg(AADDQ, w-1, D_DI); + gconreg(addptr, w-1, D_SI); + gconreg(addptr, w-1, D_DI); - gconreg(AMOVQ, c, D_CX); + gconreg(movptr, c, D_CX); gins(AREP, N, N); // repeat gins(AMOVSB, N, N); // MOVB *(SI)-,*(DI)- } if(q > 0) { if(c > 0) { - gconreg(AADDQ, -7, D_SI); - gconreg(AADDQ, -7, D_DI); + gconreg(addptr, -7, D_SI); + gconreg(addptr, -7, D_DI); } else { - gconreg(AADDQ, w-8, D_SI); - gconreg(AADDQ, w-8, D_DI); + gconreg(addptr, w-8, D_SI); + gconreg(addptr, w-8, D_DI); } - gconreg(AMOVQ, q, D_CX); + gconreg(movptr, q, D_CX); gins(AREP, N, N); // repeat gins(AMOVSQ, N, N); // MOVQ *(SI)-,*(DI)- } @@ -1427,23 +1449,48 @@ sgen(Node *n, Node *ns, int64 w) gins(ACLD, N, N); } else { // normal direction - if(q >= 4) { - gconreg(AMOVQ, q, D_CX); + if(q > 128 || (nacl && q >= 4)) { + gconreg(movptr, q, D_CX); gins(AREP, N, N); // repeat gins(AMOVSQ, N, N); // MOVQ *(SI)+,*(DI)+ + } else if (q >= 4) { + p = gins(ADUFFCOPY, N, N); + p->to.type = D_ADDR; + p->to.sym = linksym(pkglookup("duffcopy", runtimepkg)); + // 14 and 128 = magic constants: see ../../pkg/runtime/asm_amd64.s + p->to.offset = 14*(128-q); } else while(q > 0) { gins(AMOVSQ, N, N); // MOVQ *(SI)+,*(DI)+ q--; } - - if(c >= 4) { - gins(AMOVSL, N, N); // MOVL *(SI)+,*(DI)+ - c -= 4; - } - while(c > 0) { - gins(AMOVSB, N, N); // MOVB *(SI)+,*(DI)+ - c--; + // copy the remaining c bytes + if(w < 4 || c <= 1 || (odst < osrc && osrc < odst+w)) { + while(c > 0) { + gins(AMOVSB, N, N); // MOVB *(SI)+,*(DI)+ + c--; + } + } else if(w < 8 || c <= 4) { + nodsi.op = OINDREG; + noddi.op = OINDREG; + nodsi.type = types[TINT32]; + noddi.type = types[TINT32]; + if(c > 4) { + nodsi.xoffset = 0; + noddi.xoffset = 0; + gmove(&nodsi, &noddi); + } + nodsi.xoffset = c-4; + noddi.xoffset = c-4; + gmove(&nodsi, &noddi); + } else { + nodsi.op = OINDREG; + noddi.op = OINDREG; + nodsi.type = types[TINT64]; + noddi.type = types[TINT64]; + nodsi.xoffset = c-8; + noddi.xoffset = c-8; + gmove(&nodsi, &noddi); } } @@ -1513,7 +1560,7 @@ componentgen(Node *nr, Node *nl) fatal("componentgen: not a TFIELD: %lT", t); fldcount++; } - if(fldcount == 0 || fldcount > 3) + if(fldcount == 0 || fldcount > 4) goto no; break; @@ -1538,10 +1585,19 @@ componentgen(Node *nr, Node *nl) freer = 1; } } + + // nl and nr are 'cadable' which basically means they are names (variables) now. + // If they are the same variable, don't generate any code, because the + // VARDEF we generate will mark the old value as dead incorrectly. + // (And also the assignments are useless.) + if(nr != N && nl->op == ONAME && nr->op == ONAME && nl == nr) + goto yes; switch(nl->type->etype) { case TARRAY: // componentgen for arrays. + if(nl->op == ONAME) + gvardef(nl); t = nl->type; if(!isslice(t)) { nodl.type = t->type; @@ -1591,6 +1647,8 @@ componentgen(Node *nr, Node *nl) goto yes; case TSTRING: + if(nl->op == ONAME) + gvardef(nl); nodl.xoffset += Array_array; nodl.type = ptrto(types[TUINT8]); @@ -1614,6 +1672,8 @@ componentgen(Node *nr, Node *nl) goto yes; case TINTER: + if(nl->op == ONAME) + gvardef(nl); nodl.xoffset += Array_array; nodl.type = ptrto(types[TUINT8]); @@ -1637,6 +1697,8 @@ componentgen(Node *nr, Node *nl) goto yes; case TSTRUCT: + if(nl->op == ONAME) + gvardef(nl); loffset = nodl.xoffset; roffset = nodr.xoffset; // funarg structs may not begin at offset zero. diff --git a/src/cmd/6g/galign.c b/src/cmd/6g/galign.c index 526c04c06..1d32c5a61 100644 --- a/src/cmd/6g/galign.c +++ b/src/cmd/6g/galign.c @@ -8,9 +8,22 @@ int thechar = '6'; char* thestring = "amd64"; +LinkArch* thelinkarch = &linkamd64; + +void +linkarchinit(void) +{ + if(strcmp(getgoarch(), "amd64p32") == 0) + thelinkarch = &linkamd64p32; +} vlong MAXWIDTH = 1LL<<50; +int addptr = AADDQ; +int movptr = AMOVQ; +int leaptr = ALEAQ; +int cmpptr = ACMPQ; + /* * go declares several platform-specific type aliases: * int, uint, float, and uintptr @@ -28,6 +41,19 @@ betypeinit(void) { widthptr = 8; widthint = 8; + widthreg = 8; + if(strcmp(getgoarch(), "amd64p32") == 0) { + widthptr = 4; + widthint = 4; + addptr = AADDL; + movptr = AMOVL; + leaptr = ALEAL; + cmpptr = ACMPL; + typedefs[0].sameas = TINT32; + typedefs[1].sameas = TUINT32; + typedefs[2].sameas = TUINT32; + + } zprog.link = P; zprog.as = AGOK; @@ -36,5 +62,5 @@ betypeinit(void) zprog.from.scale = 0; zprog.to = zprog.from; - listinit(); + listinit6(); } diff --git a/src/cmd/6g/gg.h b/src/cmd/6g/gg.h index 3ef59c788..a5da17d61 100644 --- a/src/cmd/6g/gg.h +++ b/src/cmd/6g/gg.h @@ -9,56 +9,25 @@ #include "../gc/go.h" #include "../6l/6.out.h" -typedef struct Addr Addr; - -struct Addr -{ - vlong offset; - - union { - double dval; - vlong vval; - Prog* branch; - char sval[NSNAME]; - } u; - - Sym* gotype; - Sym* sym; - Node* node; - int64 width; - uchar type; - uchar index; - uchar etype; - uchar scale; /* doubles as width in DATA op */ -}; -#define A ((Addr*)0) - -struct Prog -{ - 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 - Prog* link; // next instruction in this func - void* opt; // for optimizer passes -}; - #define TEXTFLAG from.scale EXTERN int32 dynloc; EXTERN uchar reg[D_NONE]; EXTERN int32 pcloc; // instruction counter EXTERN Strlit emptystring; -extern char* anames[]; EXTERN Prog zprog; EXTERN Node* newproc; EXTERN Node* deferproc; EXTERN Node* deferreturn; EXTERN Node* panicindex; EXTERN Node* panicslice; +EXTERN Node* panicdiv; EXTERN Node* throwreturn; extern vlong unmappedzero; +extern int addptr; +extern int cmpptr; +extern int movptr; +extern int leaptr; /* * ggen.c @@ -150,14 +119,6 @@ void datagostring(Strlit*, Addr*); /* * list.c */ -int Aconv(Fmt*); -int Dconv(Fmt*); -int Pconv(Fmt*); -int Rconv(Fmt*); -int Yconv(Fmt*); void listinit(void); void zaddr(Biobuf*, Addr*, int, int); - -#pragma varargck type "D" Addr* -#pragma varargck type "lD" Addr* diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c index 9fad9f7f1..c385798f2 100644 --- a/src/cmd/6g/ggen.c +++ b/src/cmd/6g/ggen.c @@ -9,59 +9,110 @@ #include "gg.h" #include "opt.h" -static Prog* appendp(Prog*, int, int, vlong, int, vlong); +static Prog *appendpp(Prog*, int, int, vlong, int, vlong); +static Prog *zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *ax); void -defframe(Prog *ptxt, Bvec *bv) +defframe(Prog *ptxt) { - int i, j; - uint32 frame; + uint32 frame, ax; Prog *p; + vlong hi, lo; + NodeList *l; + Node *n; // fill in argument size ptxt->to.offset = rnd(curfn->type->argwid, widthptr); // fill in final stack size ptxt->to.offset <<= 32; - frame = rnd(stksize+maxarg, widthptr); + frame = rnd(stksize+maxarg, widthreg); ptxt->to.offset |= frame; - - // insert code to clear pointered part of the frame, - // so that garbage collector only sees initialized values + + // insert code to zero ambiguously live variables + // so that the garbage collector only sees initialized values // when it looks for pointers. p = ptxt; - if(stkzerosize >= 8*widthptr) { - p = appendp(p, AMOVQ, D_CONST, 0, D_AX, 0); - p = appendp(p, AMOVQ, D_CONST, stkzerosize/widthptr, D_CX, 0); - p = appendp(p, ALEAQ, D_SP+D_INDIR, frame-stkzerosize, D_DI, 0); - p = appendp(p, AREP, D_NONE, 0, D_NONE, 0); - appendp(p, ASTOSQ, D_NONE, 0, D_NONE, 0); - } else { - j = (stkptrsize - stkzerosize)/widthptr * 2; - for(i=0; idcl; l != nil; l = l->next) { + n = l->n; + if(!n->needzero) + continue; + if(n->class != PAUTO) + fatal("needzero class %d", n->class); + if(n->type->width % widthptr != 0 || n->xoffset % widthptr != 0 || n->type->width == 0) + fatal("var %lN has size %d offset %d", n, (int)n->type->width, (int)n->xoffset); + + if(lo != hi && n->xoffset + n->type->width >= lo - 2*widthreg) { + // merge with range we already have + lo = n->xoffset; + continue; } + // zero old range + p = zerorange(p, frame, lo, hi, &ax); + + // set new range + hi = n->xoffset + n->type->width; + lo = n->xoffset; } + // zero final range + zerorange(p, frame, lo, hi, &ax); } static Prog* -appendp(Prog *p, int as, int ftype, vlong foffset, int ttype, vlong toffset) +zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *ax) +{ + vlong cnt, i; + + cnt = hi - lo; + if(cnt == 0) + return p; + if(*ax == 0) { + p = appendpp(p, AMOVQ, D_CONST, 0, D_AX, 0); + *ax = 1; + } + if(cnt % widthreg != 0) { + // should only happen with nacl + if(cnt % widthptr != 0) + fatal("zerorange count not a multiple of widthptr %d", cnt); + p = appendpp(p, AMOVL, D_AX, 0, D_SP+D_INDIR, frame+lo); + lo += widthptr; + cnt -= widthptr; + } + if(cnt <= 4*widthreg) { + for(i = 0; i < cnt; i += widthreg) { + p = appendpp(p, AMOVQ, D_AX, 0, D_SP+D_INDIR, frame+lo+i); + } + } else if(!nacl && (cnt <= 128*widthreg)) { + p = appendpp(p, leaptr, D_SP+D_INDIR, frame+lo, D_DI, 0); + p = appendpp(p, ADUFFZERO, D_NONE, 0, D_ADDR, 2*(128-cnt/widthreg)); + p->to.sym = linksym(pkglookup("duffzero", runtimepkg)); + } else { + p = appendpp(p, AMOVQ, D_CONST, cnt/widthreg, D_CX, 0); + p = appendpp(p, leaptr, D_SP+D_INDIR, frame+lo, D_DI, 0); + p = appendpp(p, AREP, D_NONE, 0, D_NONE, 0); + p = appendpp(p, ASTOSQ, D_NONE, 0, D_NONE, 0); + } + return p; +} + +static Prog* +appendpp(Prog *p, int as, int ftype, vlong foffset, int ttype, vlong toffset) { Prog *q; - - q = mal(sizeof(*q)); - clearp(q); - q->as = as; - q->lineno = p->lineno; - q->from.type = ftype; - q->from.offset = foffset; - q->to.type = ttype; - q->to.offset = toffset; - q->link = p->link; - p->link = q; - return q; + q = mal(sizeof(*q)); + clearp(q); + q->as = as; + q->lineno = p->lineno; + q->from.type = ftype; + q->from.offset = foffset; + q->to.type = ttype; + q->to.offset = toffset; + q->link = p->link; + p->link = q; + return q; } // Sweep the prog list to mark any used nodes. @@ -69,13 +120,13 @@ void markautoused(Prog* p) { for (; p; p = p->link) { - if (p->as == ATYPE) + if (p->as == ATYPE || p->as == AVARDEF || p->as == AVARKILL) continue; - if (p->from.type == D_AUTO && p->from.node) + if (p->from.node) p->from.node->used = 1; - if (p->to.type == D_AUTO && p->to.node) + if (p->to.node) p->to.node->used = 1; } } @@ -91,6 +142,16 @@ fixautoused(Prog *p) *lp = p->link; continue; } + if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.node && !p->to.node->used) { + // Cannot remove VARDEF instruction, because - unlike TYPE handled above - + // VARDEFs are interspersed with other code, and a jump might be using the + // VARDEF as a target. Replace with a no-op instead. A later pass will remove + // the no-ops. + p->to.type = D_NONE; + p->to.node = N; + p->as = ANOP; + continue; + } if (p->from.type == D_AUTO && p->from.node) p->from.offset += p->from.node->stkdelta; @@ -179,17 +240,21 @@ ginscall(Node *f, int proc) case 1: // call in new proc (go) case 2: // deferred call (defer) - nodreg(®, types[TINT64], D_CX); - if(flag_largemodel) { - regalloc(&r1, f->type, f); + nodconst(&con, types[TINT64], argsize(f->type)); + if(widthptr == 4) { + nodreg(&r1, types[TINT32], D_CX); gmove(f, &r1); - gins(APUSHQ, &r1, N); - regfree(&r1); + nodreg(®, types[TINT64], D_CX); + nodconst(&r1, types[TINT64], 32); + gins(ASHLQ, &r1, ®); + gins(AORQ, &con, ®); + gins(APUSHQ, ®, N); } else { - gins(APUSHQ, f, N); + nodreg(®, types[TINT64], D_CX); + gmove(f, ®); + gins(APUSHQ, ®, N); + gins(APUSHQ, &con, N); } - nodconst(&con, types[TINT32], argsize(f->type)); - gins(APUSHQ, &con, N); if(proc == 1) ginscall(newproc, 0); else { @@ -197,12 +262,16 @@ ginscall(Node *f, int proc) fatal("hasdefer=0 but has defer"); ginscall(deferproc, 0); } + nodreg(®, types[TINT64], D_CX); gins(APOPQ, N, ®); - gins(APOPQ, N, ®); + if(widthptr == 8) + gins(APOPQ, N, ®); if(proc == 2) { nodreg(®, types[TINT64], D_AX); gins(ATESTQ, ®, ®); - patch(gbranch(AJNE, T, -1), retpc); + p = gbranch(AJEQ, T, +1); + cgen_ret(N); + patch(p, pc); } break; } @@ -386,11 +455,11 @@ cgen_aret(Node *n, Node *res) if(res->op != OREGISTER) { regalloc(&nod2, types[tptr], res); - gins(ALEAQ, &nod1, &nod2); - gins(AMOVQ, &nod2, res); + gins(leaptr, &nod1, &nod2); + gins(movptr, &nod2, res); regfree(&nod2); } else - gins(ALEAQ, &nod1, res); + gins(leaptr, &nod1, res); } /* @@ -402,15 +471,15 @@ cgen_ret(Node *n) { Prog *p; - genlist(n->list); // copy out args - if(hasdefer || curfn->exit) { - gjmp(retpc); - return; - } + if(n != N) + genlist(n->list); // copy out args + if(hasdefer) + ginscall(deferreturn, 0); + genlist(curfn->exit); p = gins(ARET, N, N); - if(n->op == ORETJMP) { + if(n != N && n->op == ORETJMP) { p->to.type = D_EXTERN; - p->to.sym = n->left->sym; + p->to.sym = linksym(n->left->sym); } } @@ -633,6 +702,18 @@ dodiv(int op, Node *nl, Node *nr, Node *res) } p2 = P; + if(nacl) { + // Native Client does not relay the divide-by-zero trap + // to the executing program, so we must insert a check + // for ourselves. + nodconst(&n4, t, 0); + gins(optoas(OCMP, t), &n3, &n4); + p1 = gbranch(optoas(ONE, t), T, +1); + if(panicdiv == N) + panicdiv = sysfunc("panicdivide"); + ginscall(panicdiv, -1); + patch(p1, pc); + } if(check) { nodconst(&n4, t, -1); gins(optoas(OCMP, t), &n3, &n4); @@ -1025,13 +1106,13 @@ void clearfat(Node *nl) { int64 w, c, q; - Node n1, oldn1, ax, oldax; + Node n1, oldn1, ax, oldax, di, z; + Prog *p; /* clear a fat object */ if(debug['g']) dump("\nclearfat", nl); - w = nl->type->width; // Avoid taking the address for simple enough types. if(componentgen(N, nl)) @@ -1044,22 +1125,41 @@ clearfat(Node *nl) agen(nl, &n1); savex(D_AX, &ax, &oldax, N, types[tptr]); - gconreg(AMOVQ, 0, D_AX); + gconreg(AMOVL, 0, D_AX); - if(q >= 4) { - gconreg(AMOVQ, q, D_CX); + if(q > 128 || (q >= 4 && nacl)) { + gconreg(movptr, q, D_CX); gins(AREP, N, N); // repeat gins(ASTOSQ, N, N); // STOQ AL,*(DI)+ + } else if(q >= 4) { + p = gins(ADUFFZERO, N, N); + p->to.type = D_ADDR; + p->to.sym = linksym(pkglookup("duffzero", runtimepkg)); + // 2 and 128 = magic constants: see ../../pkg/runtime/asm_amd64.s + p->to.offset = 2*(128-q); } else while(q > 0) { gins(ASTOSQ, N, N); // STOQ AL,*(DI)+ q--; } - if(c >= 4) { - gconreg(AMOVQ, c, D_CX); - gins(AREP, N, N); // repeat - gins(ASTOSB, N, N); // STOB AL,*(DI)+ + z = ax; + di = n1; + if(w >= 8 && c >= 4) { + di.op = OINDREG; + di.type = z.type = types[TINT64]; + p = gins(AMOVQ, &z, &di); + p->to.scale = 1; + p->to.offset = c-8; + } else if(c >= 4) { + di.op = OINDREG; + di.type = z.type = types[TINT32]; + p = gins(AMOVL, &z, &di); + if(c > 4) { + p = gins(AMOVL, &z, &di); + p->to.scale = 1; + p->to.offset = c-4; + } } else while(c > 0) { gins(ASTOSB, N, N); // STOB AL,*(DI)+ @@ -1095,9 +1195,9 @@ expandchecks(Prog *firstp) p->link = p1; p1->lineno = p->lineno; p2->lineno = p->lineno; - p1->loc = 9999; - p2->loc = 9999; - p->as = ACMPQ; + p1->pc = 9999; + p2->pc = 9999; + p->as = cmpptr; p->to.type = D_CONST; p->to.offset = 0; p1->as = AJNE; diff --git a/src/cmd/6g/gobj.c b/src/cmd/6g/gobj.c index a9bd5e833..04e837b13 100644 --- a/src/cmd/6g/gobj.c +++ b/src/cmd/6g/gobj.c @@ -32,231 +32,6 @@ #include #include "gg.h" -void -zname(Biobuf *b, Sym *s, int t) -{ - BPUTLE2(b, ANAME); /* as */ - BPUTC(b, t); /* type */ - BPUTC(b, s->sym); /* sym */ - - Bputname(b, s); -} - -void -zfile(Biobuf *b, char *p, int n) -{ - BPUTLE2(b, ANAME); - BPUTC(b, D_FILE); - BPUTC(b, 1); - BPUTC(b, '<'); - Bwrite(b, p, n); - BPUTC(b, 0); -} - -void -zhist(Biobuf *b, int line, vlong offset) -{ - Addr a; - - BPUTLE2(b, AHISTORY); - BPUTLE4(b, line); - zaddr(b, &zprog.from, 0, 0); - a = zprog.to; - if(offset != 0) { - a.offset = offset; - a.type = D_CONST; - } - zaddr(b, &a, 0, 0); -} - -void -zaddr(Biobuf *b, Addr *a, int s, int gotype) -{ - int32 l; - uint64 e; - int i, t; - char *n; - - t = 0; - if(a->index != D_NONE || a->scale != 0) - t |= T_INDEX; - if(s != 0) - t |= T_SYM; - if(gotype != 0) - t |= T_GOTYPE; - - switch(a->type) { - - case D_BRANCH: - if(a->u.branch == nil) - fatal("unpatched branch"); - a->offset = a->u.branch->loc; - - default: - t |= T_TYPE; - - case D_NONE: - if(a->offset != 0) { - t |= T_OFFSET; - l = a->offset; - if((vlong)l != a->offset) - t |= T_64; - } - break; - case D_FCONST: - t |= T_FCONST; - break; - case D_SCONST: - t |= T_SCONST; - break; - } - BPUTC(b, t); - - if(t & T_INDEX) { /* implies index, scale */ - BPUTC(b, a->index); - BPUTC(b, a->scale); - } - if(t & T_OFFSET) { /* implies offset */ - l = a->offset; - BPUTLE4(b, l); - if(t & T_64) { - l = a->offset>>32; - BPUTLE4(b, l); - } - } - if(t & T_SYM) /* implies sym */ - BPUTC(b, s); - if(t & T_FCONST) { - ieeedtod(&e, a->u.dval); - BPUTLE4(b, e); - BPUTLE4(b, e >> 32); - return; - } - if(t & T_SCONST) { - n = a->u.sval; - for(i=0; itype); - if(t & T_GOTYPE) - BPUTC(b, gotype); -} - -static struct { - struct { Sym *sym; short type; } h[NSYM]; - int sym; -} z; - -static void -zsymreset(void) -{ - for(z.sym=0; z.symsym; - if(i < 0 || i >= NSYM) - i = 0; - if(z.h[i].type == t && z.h[i].sym == s) - return i; - i = z.sym; - s->sym = i; - zname(bout, s, t); - z.h[i].sym = s; - z.h[i].type = t; - if(++z.sym >= NSYM) - z.sym = 1; - *new = 1; - return i; -} - -static int -zsymaddr(Addr *a, int *new) -{ - int t; - - t = a->type; - if(t == D_ADDR) - t = a->index; - return zsym(a->sym, t, new); -} - -void -dumpfuncs(void) -{ - Plist *pl; - int sf, st, gf, gt, new; - Sym *s; - Prog *p; - - zsymreset(); - - // fix up pc - pcloc = 0; - for(pl=plist; pl!=nil; pl=pl->link) { - if(isblank(pl->name)) - continue; - for(p=pl->firstpc; p!=P; p=p->link) { - p->loc = pcloc; - if(p->as != ADATA && p->as != AGLOBL) - pcloc++; - } - } - - // put out functions - for(pl=plist; pl!=nil; pl=pl->link) { - if(isblank(pl->name)) - continue; - - // -S prints code; -SS prints code and data - if(debug['S'] && (pl->name || debug['S']>1)) { - s = S; - if(pl->name != N) - s = pl->name->sym; - print("\n--- prog list \"%S\" ---\n", s); - for(p=pl->firstpc; p!=P; p=p->link) - print("%P\n", p); - } - - for(p=pl->firstpc; p!=P; p=p->link) { - for(;;) { - sf = zsymaddr(&p->from, &new); - gf = zsym(p->from.gotype, D_EXTERN, &new); - if(new && sf == gf) - continue; - st = zsymaddr(&p->to, &new); - if(new && (st == sf || st == gf)) - continue; - gt = zsym(p->to.gotype, D_EXTERN, &new); - if(new && (gt == sf || gt == gf || gt == st)) - continue; - break; - } - - BPUTLE2(bout, p->as); - BPUTLE4(bout, p->lineno); - zaddr(bout, &p->from, sf, gf); - zaddr(bout, &p->to, st, gt); - } - } -} - int dsname(Sym *s, int off, char *t, int n) { @@ -267,7 +42,7 @@ dsname(Sym *s, int off, char *t, int n) p->from.index = D_NONE; p->from.offset = off; p->from.scale = n; - p->from.sym = s; + p->from.sym = linksym(s); p->to.type = D_SCONST; p->to.index = D_NONE; @@ -286,7 +61,7 @@ datastring(char *s, int len, Addr *a) sym = stringsym(s, len); a->type = D_EXTERN; - a->sym = sym; + a->sym = linksym(sym); a->node = sym->def; a->offset = widthptr+widthint; // skip header a->etype = simtype[TINT]; @@ -303,7 +78,7 @@ datagostring(Strlit *sval, Addr *a) sym = stringsym(sval->s, sval->len); a->type = D_EXTERN; - a->sym = sym; + a->sym = linksym(sym); a->node = sym->def; a->offset = 0; // header a->etype = TINT32; @@ -377,7 +152,7 @@ dstringptr(Sym *s, int off, char *str) p = gins(ADATA, N, N); p->from.type = D_EXTERN; p->from.index = D_NONE; - p->from.sym = s; + p->from.sym = linksym(s); p->from.offset = off; p->from.scale = widthptr; @@ -402,7 +177,7 @@ dgostrlitptr(Sym *s, int off, Strlit *lit) p = gins(ADATA, N, N); p->from.type = D_EXTERN; p->from.index = D_NONE; - p->from.sym = s; + p->from.sym = linksym(s); p->from.offset = off; p->from.scale = widthptr; datagostring(lit, &p->to); @@ -430,27 +205,6 @@ dgostringptr(Sym *s, int off, char *str) return dgostrlitptr(s, off, lit); } -int -duintxx(Sym *s, int off, uint64 v, int wid) -{ - Prog *p; - - off = rnd(off, wid); - - p = gins(ADATA, N, N); - p->from.type = D_EXTERN; - p->from.index = D_NONE; - p->from.sym = s; - p->from.offset = off; - p->from.scale = wid; - p->to.type = D_CONST; - p->to.index = D_NONE; - p->to.offset = v; - off += wid; - - return off; -} - int dsymptr(Sym *s, int off, Sym *x, int xoff) { @@ -461,12 +215,12 @@ dsymptr(Sym *s, int off, Sym *x, int xoff) p = gins(ADATA, N, N); p->from.type = D_EXTERN; p->from.index = D_NONE; - p->from.sym = s; + p->from.sym = linksym(s); p->from.offset = off; p->from.scale = widthptr; p->to.type = D_ADDR; p->to.index = D_EXTERN; - p->to.sym = x; + p->to.sym = linksym(x); p->to.offset = xoff; off += widthptr; diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c index 7318909bb..e4d00bf41 100644 --- a/src/cmd/6g/gsubr.c +++ b/src/cmd/6g/gsubr.c @@ -46,7 +46,7 @@ clearp(Prog *p) p->from.index = D_NONE; p->to.type = D_NONE; p->to.index = D_NONE; - p->loc = pcloc; + p->pc = pcloc; pcloc++; } @@ -136,7 +136,7 @@ patch(Prog *p, Prog *to) if(p->to.type != D_BRANCH) fatal("patch: not a branch"); p->to.u.branch = to; - p->to.offset = to->loc; + p->to.offset = to->pc; } Prog* @@ -160,12 +160,7 @@ newplist(void) { Plist *pl; - pl = mal(sizeof(*pl)); - if(plist == nil) - plist = pl; - else - plast->link = pl; - plast = pl; + pl = linknewplist(ctxt); pc = mal(sizeof(*pc)); clearp(pc); @@ -198,8 +193,8 @@ ggloblnod(Node *nam) p = gins(AGLOBL, nam, N); p->lineno = nam->lineno; - p->from.gotype = ngotype(nam); - p->to.sym = S; + p->from.sym->gotype = linksym(ngotype(nam)); + p->to.sym = nil; p->to.type = D_CONST; p->to.offset = nam->type->width; if(nam->readonly) @@ -216,7 +211,7 @@ gtrack(Sym *s) p = gins(AUSEFIELD, N, N); p->from.type = D_EXTERN; p->from.index = D_NONE; - p->from.sym = s; + p->from.sym = linksym(s); } void @@ -237,7 +232,7 @@ ggloblsym(Sym *s, int32 width, int dupok, int rodata) p = gins(AGLOBL, N, N); p->from.type = D_EXTERN; p->from.index = D_NONE; - p->from.sym = s; + p->from.sym = linksym(s); p->to.type = D_CONST; p->to.index = D_NONE; p->to.offset = width; @@ -272,7 +267,7 @@ afunclit(Addr *a, Node *n) if(a->type == D_ADDR && a->index == D_EXTERN) { a->type = D_EXTERN; a->index = D_NONE; - a->sym = n->sym; + a->sym = linksym(n->sym); } } @@ -301,6 +296,11 @@ ginit(void) for(i=0; ietype != TFIELD) fatal("nodarg: not field %T", t); + + if(fp == 1) { + for(l=curfn->dcl; l; l=l->next) { + n = l->n; + if((n->class == PPARAM || n->class == PPARAMOUT) && !isblanksym(t->sym) && n->sym == t->sym) + return n; + } + } n = nod(ONAME, N, N); n->type = t->type; @@ -525,7 +539,16 @@ gconreg(int as, vlong c, int reg) { Node nr; - nodreg(&nr, types[TINT64], reg); + switch(as) { + case AADDL: + case AMOVL: + case ALEAL: + nodreg(&nr, types[TINT32], reg); + break; + default: + nodreg(&nr, types[TINT64], reg); + } + ginscon(as, c, &nr); } @@ -538,10 +561,18 @@ ginscon(int as, vlong c, Node *n2) { Node n1, ntmp; - nodconst(&n1, types[TINT64], c); + switch(as) { + case AADDL: + case AMOVL: + case ALEAL: + nodconst(&n1, types[TINT32], c); + break; + default: + nodconst(&n1, types[TINT64], c); + } if(as != AMOVQ && (c < -(1LL<<31) || c >= 1LL<<31)) { - // cannot have 64-bit immediokate in ADD, etc. + // cannot have 64-bit immediate in ADD, etc. // instead, MOV into register first. regalloc(&ntmp, types[TINT64], N); gins(AMOVQ, &n1, &ntmp); @@ -1098,10 +1129,12 @@ fixlargeoffset(Node *n) void naddr(Node *n, Addr *a, int canemitcode) { + Sym *s; + a->scale = 0; a->index = D_NONE; a->type = D_NONE; - a->gotype = S; + a->gotype = nil; a->node = N; a->width = 0; if(n == N) @@ -1119,7 +1152,7 @@ naddr(Node *n, Addr *a, int canemitcode) case OREGISTER: a->type = n->val.u.reg; - a->sym = S; + a->sym = nil; break; // case OINDEX: @@ -1144,7 +1177,7 @@ naddr(Node *n, Addr *a, int canemitcode) case OINDREG: a->type = n->val.u.reg+D_INDIR; - a->sym = n->sym; + a->sym = linksym(n->sym); a->offset = n->xoffset; if(a->offset != (int32)a->offset) yyerror("offset %lld too large for OINDREG", a->offset); @@ -1156,20 +1189,22 @@ naddr(Node *n, Addr *a, int canemitcode) a->etype = simtype[n->left->type->etype]; a->width = n->left->type->width; a->offset = n->xoffset; - a->sym = n->left->sym; + a->sym = linksym(n->left->sym); a->type = D_PARAM; a->node = n->left->orig; break; case OCLOSUREVAR: + if(!curfn->needctxt) + fatal("closurevar without needctxt"); a->type = D_DX+D_INDIR; - a->sym = S; + a->sym = nil; a->offset = n->xoffset; break; case OCFUNC: naddr(n->left, a, canemitcode); - a->sym = n->left->sym; + a->sym = linksym(n->left->sym); break; case ONAME: @@ -1177,17 +1212,17 @@ naddr(Node *n, Addr *a, int canemitcode) if(n->type != T) a->etype = simtype[n->type->etype]; a->offset = n->xoffset; - a->sym = n->sym; + s = n->sym; a->node = n->orig; //if(a->node >= (Node*)&n) // fatal("stack node"); - if(a->sym == S) - a->sym = lookup(".noname"); + if(s == S) + s = lookup(".noname"); if(n->method) { if(n->type != T) if(n->type->sym != S) if(n->type->sym->pkg != nil) - a->sym = pkglookup(a->sym->name, n->type->sym->pkg); + s = pkglookup(s->name, n->type->sym->pkg); } switch(n->class) { @@ -1207,9 +1242,10 @@ naddr(Node *n, Addr *a, int canemitcode) a->index = D_EXTERN; a->type = D_ADDR; a->width = widthptr; - a->sym = funcsym(a->sym); + s = funcsym(s); break; } + a->sym = linksym(s); break; case OLITERAL: @@ -1223,7 +1259,7 @@ naddr(Node *n, Addr *a, int canemitcode) break; case CTINT: case CTRUNE: - a->sym = S; + a->sym = nil; a->type = D_CONST; a->offset = mpgetfix(n->val.u.xval); break; @@ -1231,12 +1267,12 @@ naddr(Node *n, Addr *a, int canemitcode) datagostring(n->val.u.sval, a); break; case CTBOOL: - a->sym = S; + a->sym = nil; a->type = D_CONST; a->offset = n->val.u.bval; break; case CTNIL: - a->sym = S; + a->sym = nil; a->type = D_CONST; a->offset = 0; break; @@ -1273,7 +1309,7 @@ naddr(Node *n, Addr *a, int canemitcode) naddr(n->left, a, canemitcode); if(a->type == D_CONST && a->offset == 0) break; // ptr(nil) - a->etype = simtype[TUINTPTR]; + a->etype = simtype[tptr]; a->offset += Array_array; a->width = widthptr; break; @@ -1506,12 +1542,14 @@ optoas(int op, Type *t) case CASE(OADD, TINT32): case CASE(OADD, TUINT32): case CASE(OADD, TPTR32): + case CASE(OADDPTR, TPTR32): a = AADDL; break; case CASE(OADD, TINT64): case CASE(OADD, TUINT64): case CASE(OADD, TPTR64): + case CASE(OADDPTR, TPTR64): a = AADDQ; break; @@ -2042,7 +2080,7 @@ odot: for(i=1; i= 0) fatal("can't happen"); - gins(AMOVQ, &n1, reg); + gins(movptr, &n1, reg); cgen_checknil(reg); n1.xoffset = -(oary[i]+1); } @@ -2254,7 +2292,7 @@ oindex_const_sudo: if(reg->op == OEMPTY) regalloc(reg, types[tptr], N); - p1 = gins(AMOVQ, N, reg); + p1 = gins(movptr, N, reg); p1->from = *a; n2 = *reg; diff --git a/src/cmd/6g/list.c b/src/cmd/6g/list.c deleted file mode 100644 index 9d27a6a09..000000000 --- a/src/cmd/6g/list.c +++ /dev/null @@ -1,364 +0,0 @@ -// Derived from Inferno utils/6c/list.c -// http://code.google.com/p/inferno-os/source/browse/utils/6c/list.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 -#include -#include "gg.h" - -static int sconsize; -void -listinit(void) -{ - - fmtinstall('A', Aconv); // as - fmtinstall('P', Pconv); // Prog* - fmtinstall('D', Dconv); // Addr* - fmtinstall('R', Rconv); // reg - fmtinstall('Y', Yconv); // sconst -} - -int -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), "%.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), "%.4d (%L) %-7A %D/%d,%D", - p->loc, p->lineno, p->as, &p->from, sconsize, &p->to); - break; - - case ATEXT: - 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); -} - -int -Dconv(Fmt *fp) -{ - char str[STRINGSZ], s[STRINGSZ]; - Addr *a; - int i; - uint32 d1, d2; - - a = va_arg(fp->args, Addr*); - i = a->type; - if(i >= D_INDIR) { - if(a->offset) - snprint(str, sizeof(str), "%lld(%R)", a->offset, i-D_INDIR); - else - snprint(str, sizeof(str), "(%R)", i-D_INDIR); - goto brk; - } - switch(i) { - - default: - if(a->offset) - snprint(str, sizeof(str), "$%lld,%R", a->offset, i); - else - snprint(str, sizeof(str), "%R", i); - break; - - case D_NONE: - str[0] = 0; - break; - - case D_BRANCH: - if(a->u.branch == nil) - snprint(str, sizeof(str), ""); - else - snprint(str, sizeof(str), "%d", a->u.branch->loc); - break; - - case D_EXTERN: - snprint(str, sizeof(str), "%S+%lld(SB)", a->sym, a->offset); - break; - - case D_STATIC: - snprint(str, sizeof(str), "%S<>+%lld(SB)", a->sym, a->offset); - break; - - case D_AUTO: - snprint(str, sizeof(str), "%S+%lld(SP)", a->sym, a->offset); - break; - - case D_PARAM: - snprint(str, sizeof(str), "%S+%lld(FP)", a->sym, a->offset); - break; - - case D_CONST: - if(fp->flags & FmtLong) { - d1 = a->offset & 0xffffffffLL; - d2 = (a->offset>>32) & 0xffffffffLL; - snprint(str, sizeof(str), "$%lud-%lud", (ulong)d1, (ulong)d2); - break; - } - snprint(str, sizeof(str), "$%lld", a->offset); - break; - - case D_FCONST: - snprint(str, sizeof(str), "$(%.17e)", a->u.dval); - break; - - case D_SCONST: - snprint(str, sizeof(str), "$\"%Y\"", a->u.sval); - break; - - case D_ADDR: - a->type = a->index; - a->index = D_NONE; - snprint(str, sizeof(str), "$%D", a); - a->index = a->type; - a->type = D_ADDR; - goto conv; - } -brk: - if(a->index != D_NONE) { - snprint(s, sizeof(s), "(%R*%d)", (int)a->index, (int)a->scale); - strcat(str, s); - } -conv: - fmtstrcpy(fp, str); - if(a->gotype) - fmtprint(fp, "{%s}", a->gotype->name); - return 0; -} - -static char* regstr[] = -{ - "AL", /* [D_AL] */ - "CL", - "DL", - "BL", - "SPB", - "BPB", - "SIB", - "DIB", - "R8B", - "R9B", - "R10B", - "R11B", - "R12B", - "R13B", - "R14B", - "R15B", - - "AX", /* [D_AX] */ - "CX", - "DX", - "BX", - "SP", - "BP", - "SI", - "DI", - "R8", - "R9", - "R10", - "R11", - "R12", - "R13", - "R14", - "R15", - - "AH", - "CH", - "DH", - "BH", - - "F0", /* [D_F0] */ - "F1", - "F2", - "F3", - "F4", - "F5", - "F6", - "F7", - - "M0", - "M1", - "M2", - "M3", - "M4", - "M5", - "M6", - "M7", - - "X0", - "X1", - "X2", - "X3", - "X4", - "X5", - "X6", - "X7", - "X8", - "X9", - "X10", - "X11", - "X12", - "X13", - "X14", - "X15", - - "CS", /* [D_CS] */ - "SS", - "DS", - "ES", - "FS", - "GS", - - "GDTR", /* [D_GDTR] */ - "IDTR", /* [D_IDTR] */ - "LDTR", /* [D_LDTR] */ - "MSW", /* [D_MSW] */ - "TASK", /* [D_TASK] */ - - "CR0", /* [D_CR] */ - "CR1", - "CR2", - "CR3", - "CR4", - "CR5", - "CR6", - "CR7", - "CR8", - "CR9", - "CR10", - "CR11", - "CR12", - "CR13", - "CR14", - "CR15", - - "DR0", /* [D_DR] */ - "DR1", - "DR2", - "DR3", - "DR4", - "DR5", - "DR6", - "DR7", - - "TR0", /* [D_TR] */ - "TR1", - "TR2", - "TR3", - "TR4", - "TR5", - "TR6", - "TR7", - - "NONE", /* [D_NONE] */ -}; - -int -Rconv(Fmt *fp) -{ - char str[STRINGSZ]; - int r; - - r = va_arg(fp->args, int); - if(r < 0 || r >= nelem(regstr) || regstr[r] == nil) { - snprint(str, sizeof(str), "BAD_R(%d)", r); - return fmtstrcpy(fp, str); - } - return fmtstrcpy(fp, regstr[r]); -} - -int -Aconv(Fmt *fp) -{ - int i; - - i = va_arg(fp->args, int); - return fmtstrcpy(fp, anames[i]); -} - - -int -Yconv(Fmt *fp) -{ - int i, c; - char str[STRINGSZ], *p, *a; - - a = va_arg(fp->args, char*); - p = str; - for(i=0; i= 'a' && c <= 'z') || - (c >= 'A' && c <= 'Z') || - (c >= '0' && c <= '9')) { - *p++ = c; - continue; - } - *p++ = '\\'; - switch(c) { - default: - if(c < 040 || c >= 0177) - break; /* not portable */ - p[-1] = c; - continue; - case 0: - *p++ = 'z'; - continue; - case '\\': - case '"': - *p++ = c; - continue; - case '\n': - *p++ = 'n'; - continue; - case '\t': - *p++ = 't'; - continue; - } - *p++ = (c>>6) + '0'; - *p++ = ((c>>3) & 7) + '0'; - *p++ = (c & 7) + '0'; - } - *p = 0; - return fmtstrcpy(fp, str); -} diff --git a/src/cmd/6g/opt.h b/src/cmd/6g/opt.h index 3dcc3d747..bf356af0c 100644 --- a/src/cmd/6g/opt.h +++ b/src/cmd/6g/opt.h @@ -94,6 +94,7 @@ EXTERN Bits externs; EXTERN Bits params; EXTERN Bits consts; EXTERN Bits addrs; +EXTERN Bits ivar; EXTERN Bits ovar; EXTERN int change; EXTERN int32 maxnr; diff --git a/src/cmd/6g/peep.c b/src/cmd/6g/peep.c index 5ccf90103..0f2720443 100644 --- a/src/cmd/6g/peep.c +++ b/src/cmd/6g/peep.c @@ -109,7 +109,7 @@ peep(Prog *firstp) case ALEAL: case ALEAQ: if(regtyp(&p->to)) - if(p->from.sym != S) + if(p->from.sym != nil) if(p->from.index == D_NONE || p->from.index == D_CONST) conprop(r); break; @@ -306,7 +306,7 @@ pushback(Flow *r0) if(p->as != ANOP) { if(!regconsttyp(&p->from) || !regtyp(&p->to)) break; - if(copyu(p, &p0->to, A) || copyu(p0, &p->to, A)) + if(copyu(p, &p0->to, nil) || copyu(p0, &p->to, nil)) break; } if(p->as == ACALL) @@ -573,6 +573,8 @@ subprop(Flow *r0) break; } p = r->prog; + if(p->as == AVARDEF || p->as == AVARKILL) + continue; proginfo(&info, p); if(info.flags & Call) { if(debug['P'] && debug['v']) @@ -682,7 +684,7 @@ copy1(Adr *v1, Adr *v2, Flow *r, int f) if(debug['P']) print("; merge; f=%d", f); } - t = copyu(p, v2, A); + t = copyu(p, v2, nil); switch(t) { case 2: /* rar, can't split */ if(debug['P']) @@ -720,7 +722,7 @@ copy1(Adr *v1, Adr *v2, Flow *r, int f) break; } if(!f) { - t = copyu(p, v1, A); + t = copyu(p, v1, nil); if(!f && (t == 2 || t == 3 || t == 4)) { f = 1; if(debug['P']) @@ -751,7 +753,7 @@ copyu(Prog *p, Adr *v, Adr *s) switch(p->as) { case AJMP: - if(s != A) { + if(s != nil) { if(copysub(&p->to, v, s, 1)) return 1; return 0; @@ -761,7 +763,7 @@ copyu(Prog *p, Adr *v, Adr *s) return 0; case ARET: - if(s != A) + if(s != nil) return 1; return 3; @@ -773,7 +775,7 @@ copyu(Prog *p, Adr *v, Adr *s) if(v->type == p->from.type) return 2; - if(s != A) { + if(s != nil) { if(copysub(&p->to, v, s, 1)) return 1; return 0; @@ -788,6 +790,8 @@ copyu(Prog *p, Adr *v, Adr *s) return 0; } + if(p->as == AVARDEF || p->as == AVARKILL) + return 0; proginfo(&info, p); if((info.reguse|info.regset) & RtoB(v->type)) @@ -803,7 +807,7 @@ copyu(Prog *p, Adr *v, Adr *s) if(info.flags & RightWrite) { if(copyas(&p->to, v)) { - if(s != A) + if(s != nil) return copysub(&p->from, v, s, 1); if(copyau(&p->from, v)) return 4; @@ -812,7 +816,7 @@ copyu(Prog *p, Adr *v, Adr *s) } if(info.flags & (LeftAddr|LeftRead|LeftWrite|RightAddr|RightRead|RightWrite)) { - if(s != A) { + if(s != nil) { if(copysub(&p->from, v, s, 1)) return 1; return copysub(&p->to, v, s, 1); @@ -940,7 +944,7 @@ loop: return; p = r->prog; - t = copyu(p, v0, A); + t = copyu(p, v0, nil); switch(t) { case 0: // miss case 1: // use @@ -956,7 +960,7 @@ loop: if(p->from.node == p0->from.node) if(p->from.offset == p0->from.offset) if(p->from.scale == p0->from.scale) - if(p->from.u.vval == p0->from.u.vval) + if(p->from.type == D_FCONST && p->from.u.dval == p0->from.u.dval) if(p->from.index == p0->from.index) { excise(r); goto loop; diff --git a/src/cmd/6g/prog.c b/src/cmd/6g/prog.c index 90571a21a..ee68399d5 100644 --- a/src/cmd/6g/prog.c +++ b/src/cmd/6g/prog.c @@ -38,9 +38,11 @@ static ProgInfo progtable[ALAST] = { [ATEXT]= {Pseudo}, [AFUNCDATA]= {Pseudo}, [APCDATA]= {Pseudo}, - [AUNDEF]= {OK}, + [AUNDEF]= {Break}, [AUSEFIELD]= {OK}, [ACHECKNIL]= {LeftRead}, + [AVARDEF]= {Pseudo | RightWrite}, + [AVARKILL]= {Pseudo | RightWrite}, // NOP is an internal no-op that also stands // for USED and SET annotations, not the Intel opcode. @@ -142,6 +144,7 @@ static ProgInfo progtable[ALAST] = { [AJMP]= {Jump | Break | KillCarry}, + [ALEAL]= {LeftAddr | RightWrite}, [ALEAQ]= {LeftAddr | RightWrite}, [AMOVBLSX]= {SizeL | LeftRead | RightWrite | Conv}, @@ -167,6 +170,7 @@ static ProgInfo progtable[ALAST] = { [AMOVSL]= {OK, DI|SI, DI|SI}, [AMOVSQ]= {OK, DI|SI, DI|SI}, [AMOVSW]= {OK, DI|SI, DI|SI}, + [ADUFFCOPY]= {OK, DI|SI, DI|SI|CX}, [AMOVSD]= {SizeD | LeftRead | RightWrite | Move}, [AMOVSS]= {SizeF | LeftRead | RightWrite | Move}, @@ -254,6 +258,7 @@ static ProgInfo progtable[ALAST] = { [ASTOSL]= {OK, AX|DI, DI}, [ASTOSQ]= {OK, AX|DI, DI}, [ASTOSW]= {OK, AX|DI, DI}, + [ADUFFZERO]= {OK, AX|DI, DI}, [ASUBB]= {SizeB | LeftRead | RightRdwr | SetCarry}, [ASUBL]= {SizeL | LeftRead | RightRdwr | SetCarry}, diff --git a/src/cmd/6g/reg.c b/src/cmd/6g/reg.c index 63fd0deca..f3b1e55de 100644 --- a/src/cmd/6g/reg.c +++ b/src/cmd/6g/reg.c @@ -54,30 +54,6 @@ rcmp(const void *a1, const void *a2) 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); - for(z=0; zopt = nil; return; + } + firstr = (Reg*)g->start; for(r = firstr; r != R; r = (Reg*)r->f.link) { p = r->f.prog; + if(p->as == AVARDEF || p->as == AVARKILL) + continue; proginfo(&info, p); // Avoid making variables for direct-called functions. @@ -255,6 +236,26 @@ regopt(Prog *firstp) if(debug['R'] && debug['v']) dumpit("pass2", &firstr->f, 1); + /* + * pass 2.5 + * iterate propagating fat vardef covering forward + * r->act records vars with a VARDEF since the last CALL. + * (r->act will be reused in pass 5 for something else, + * but we'll be done with it by then.) + */ + active = 0; + for(r = firstr; r != R; r = (Reg*)r->f.link) { + r->f.active = 0; + r->act = zbits; + } + for(r = firstr; r != R; r = (Reg*)r->f.link) { + p = r->f.prog; + if(p->as == AVARDEF && isfat(p->to.node->type) && p->to.node->opt != nil) { + active++; + walkvardef(p->to.node, r, active); + } + } + /* * pass 3 * iterate propagating usage @@ -406,6 +407,8 @@ brk: /* * free aux structures. peep allocates new ones. */ + for(i=0; iopt = nil; flowend(g); firstr = R; @@ -454,6 +457,32 @@ brk: } } +static void +walkvardef(Node *n, Reg *r, int active) +{ + Reg *r1, *r2; + int bn; + Var *v; + + for(r1=r; r1!=R; r1=(Reg*)r1->f.s1) { + if(r1->f.active == active) + break; + r1->f.active = active; + if(r1->f.prog->as == AVARKILL && r1->f.prog->to.node == n) + break; + for(v=n->opt; v!=nil; v=v->nextinnode) { + bn = v - var; + r1->act.b[bn/32] |= 1L << (bn%32); + } + if(r1->f.prog->as == ACALL) + break; + } + + for(r2=r; r2!=r1; r2=(Reg*)r2->f.s1) + if(r2->f.s2 != nil) + walkvardef(n, (Reg*)r2->f.s2, active); +} + /* * add mov b,rn * just after r @@ -467,7 +496,7 @@ addmove(Reg *r, int bn, int rn, int f) p1 = mal(sizeof(*p1)); clearp(p1); - p1->loc = 9999; + p1->pc = 9999; p = r->f.prog; p1->link = p->link; @@ -481,12 +510,12 @@ addmove(Reg *r, int bn, int rn, int f) a->etype = v->etype; a->type = v->name; a->node = v->node; - a->sym = v->node->sym; + a->sym = linksym(v->node->sym); // need to clean this up with wptr and // some of the defaults p1->as = AMOVL; - switch(v->etype) { + switch(simtype[(uchar)v->etype]) { default: fatal("unknown type %E", v->etype); case TINT8: @@ -500,7 +529,6 @@ addmove(Reg *r, int bn, int rn, int f) break; case TINT64: case TUINT64: - case TUINTPTR: case TPTR64: p1->as = AMOVQ; break; @@ -510,8 +538,6 @@ addmove(Reg *r, int bn, int rn, int f) case TFLOAT64: p1->as = AMOVSD; break; - case TINT: - case TUINT: case TINT32: case TUINT32: case TPTR32: @@ -655,6 +681,16 @@ mkvar(Reg *r, Adr *a) if(nvar >= NVAR) { if(debug['w'] > 1 && node != N) fatal("variable not optimized: %#N", node); + + // If we're not tracking a word in a variable, mark the rest as + // having its address taken, so that we keep the whole thing + // live at all calls. otherwise we might optimize away part of + // a variable but not all of it. + for(i=0; inode == node) + v->addr = 1; + } goto none; } @@ -667,11 +703,13 @@ mkvar(Reg *r, Adr *a) v->width = w; v->addr = flag; // funny punning v->node = node; - - if(debug['R']) - print("bit=%2d et=%2E w=%d+%lld %#N %D flag=%d\n", i, et, o, w, node, a, v->addr); - - ostats.nvar++; + + // node->opt is the head of a linked list + // of Vars within the given Node, so that + // we can start at a Var and find all the other + // Vars in the same Go variable. + v->nextinnode = node->opt; + node->opt = v; bit = blsh(i); if(n == D_EXTERN || n == D_STATIC) @@ -681,6 +719,46 @@ mkvar(Reg *r, Adr *a) for(z=0; zclass == PPARAM) + for(z=0; zclass == PPARAMOUT) + for(z=0; zaddrtaken) + v->addr = 1; + + // Disable registerization for globals, because: + // (1) we might panic at any time and we want the recovery code + // to see the latest values (issue 1304). + // (2) we don't know what pointers might point at them and we want + // loads via those pointers to see updated values and vice versa (issue 7995). + // + // Disable registerization for results if using defer, because the deferred func + // might recover and return, causing the current values to be used. + if(node->class == PEXTERN || (hasdefer && node->class == PPARAMOUT)) + v->addr = 1; + + if(debug['R']) + print("bit=%2d et=%2E w=%lld+%lld %#N %D flag=%d\n", i, et, o, w, node, a, v->addr); + ostats.nvar++; + return bit; none: @@ -691,7 +769,8 @@ void prop(Reg *r, Bits ref, Bits cal) { Reg *r1, *r2; - int z; + int z, i, j; + Var *v, *v1; for(r1 = r; r1 != R; r1 = (Reg*)r1->f.p1) { for(z=0; zf.prog)) break; + + // Mark all input variables (ivar) as used, because that's what the + // liveness bitmaps say. The liveness bitmaps say that so that a + // panic will not show stale values in the parameter dump. + // Mark variables with a recent VARDEF (r1->act) as used, + // so that the optimizer flushes initializations to memory, + // so that if a garbage collection happens during this CALL, + // the collector will see initialized memory. Again this is to + // match what the liveness bitmaps say. for(z=0; zact.b[z]; ref.b[z] = 0; } + + // cal.b is the current approximation of what's live across the call. + // Every bit in cal.b is a single stack word. For each such word, + // find all the other tracked stack words in the same Go variable + // (struct/slice/string/interface) and mark them live too. + // This is necessary because the liveness analysis for the garbage + // collector works at variable granularity, not at word granularity. + // It is fundamental for slice/string/interface: the garbage collector + // needs the whole value, not just some of the words, in order to + // interpret the other bits correctly. Specifically, slice needs a consistent + // ptr and cap, string needs a consistent ptr and len, and interface + // needs a consistent type word and data word. + for(z=0; z= nvar || ((cal.b[z]>>i)&1) == 0) + continue; + v = var+z*32+i; + if(v->node->opt == nil) // v represents fixed register, not Go variable + continue; + + // v->node->opt is the head of a linked list of Vars + // corresponding to tracked words from the Go variable v->node. + // Walk the list and set all the bits. + // For a large struct this could end up being quadratic: + // after the first setting, the outer loop (for z, i) would see a 1 bit + // for all of the remaining words in the struct, and for each such + // word would go through and turn on all the bits again. + // To avoid the quadratic behavior, we only turn on the bits if + // v is the head of the list or if the head's bit is not yet turned on. + // This will set the bits at most twice, keeping the overall loop linear. + v1 = v->node->opt; + j = v1 - var; + if(v == v1 || ((cal.b[j/32]>>(j&31))&1) == 0) { + for(; v1 != nil; v1 = v1->nextinnode) { + j = v1 - var; + cal.b[j/32] |= 1<<(j&31); + } + } + } + } break; case ATEXT: @@ -729,17 +859,6 @@ prop(Reg *r, Bits ref, Bits cal) ref.b[z] = 0; } break; - - default: - // Work around for issue 1304: - // flush modified globals before each instruction. - for(z=0; zset.b[z]) | @@ -860,12 +979,11 @@ paint1(Reg *r, int bn) for(;;) { r->act.b[z] |= bb; - if(r->use1.b[z] & bb) { - change += CREF * r->f.loop; - } - - if((r->use2.b[z]|r->set.b[z]) & bb) { - change += CREF * r->f.loop; + if(r->f.prog->as != ANOP) { // don't give credit for NOPs + if(r->use1.b[z] & bb) + change += CREF * r->f.loop; + if((r->use2.b[z]|r->set.b[z]) & bb) + change += CREF * r->f.loop; } if(STORE(r) & r->regdiff.b[z] & bb) { @@ -906,7 +1024,7 @@ regset(Reg *r, uint32 bb) v.type = b & 0xFFFF? BtoR(b): BtoF(b); if(v.type == 0) fatal("zero v.type for %#ux", b); - c = copyu(r->f.prog, &v, A); + c = copyu(r->f.prog, &v, nil); if(c == 3) set |= b; bb &= ~b; @@ -925,7 +1043,7 @@ reguse(Reg *r, uint32 bb) v = zprog.from; while(b = bb & ~(bb-1)) { v.type = b & 0xFFFF? BtoR(b): BtoF(b); - c = copyu(r->f.prog, &v, A); + c = copyu(r->f.prog, &v, nil); if(c == 1 || c == 2 || c == 4) set |= b; bb &= ~b; @@ -1067,8 +1185,7 @@ paint3(Reg *r, int bn, int32 rb, int rn) void addreg(Adr *a, int rn) { - - a->sym = 0; + a->sym = nil; a->offset = 0; a->type = rn; @@ -1088,6 +1205,8 @@ int BtoR(int32 b) { b &= 0xffffL; + if(nacl) + b &= ~((1<<(D_BP-D_AX)) | (1<<(D_R15-D_AX))); if(b == 0) return 0; return bitno(b) + D_AX; @@ -1176,14 +1295,14 @@ dumpit(char *str, Flow *r0, int isreg) if(r1 != nil) { print(" pred:"); for(; r1 != nil; r1 = r1->p2link) - print(" %.4ud", r1->prog->loc); + print(" %.4ud", (int)r1->prog->pc); print("\n"); } // r1 = r->s1; // if(r1 != R) { // print(" succ:"); // for(; r1 != R; r1 = r1->s1) -// print(" %.4ud", r1->prog->loc); +// print(" %.4ud", (int)r1->prog->pc); // print("\n"); // } } diff --git a/src/cmd/6l/6.out.h b/src/cmd/6l/6.out.h index 5fa73a65b..1e2a1488f 100644 --- a/src/cmd/6l/6.out.h +++ b/src/cmd/6l/6.out.h @@ -762,6 +762,10 @@ enum as AFUNCDATA, APCDATA, ACHECKNIL, + AVARDEF, + AVARKILL, + ADUFFCOPY, + ADUFFZERO, ALAST }; @@ -846,27 +850,21 @@ enum D_DR = 95, D_TR = 103, - D_NONE = 111, + D_TLS = 111, + D_NONE = 112, - D_BRANCH = 112, - D_EXTERN = 113, - D_STATIC = 114, - D_AUTO = 115, - D_PARAM = 116, - D_CONST = 117, - D_FCONST = 118, - D_SCONST = 119, - D_ADDR = 120, - - D_FILE, - D_FILE1, + D_BRANCH = 113, + D_EXTERN = 114, + D_STATIC = 115, + D_AUTO = 116, + D_PARAM = 117, + D_CONST = 118, + D_FCONST = 119, + D_SCONST = 120, + D_ADDR = 121, D_INDIR, /* additive */ - D_SIZE = D_INDIR + D_INDIR, /* 6l internal */ - D_PCREL, - D_TLS, - T_TYPE = 1<<0, T_INDEX = 1<<1, T_OFFSET = 1<<2, @@ -890,15 +888,3 @@ enum * this is the ranlib header */ #define SYMDEF "__.GOSYMDEF" - -/* - * this is the simulated IEEE floating point - */ -typedef struct ieee Ieee; -struct ieee -{ - int32 l; /* contains ls-man 0xffffffff */ - int32 h; /* contains sign 0x80000000 - exp 0x7ff00000 - ms-man 0x000fffff */ -}; diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c index a09cc9727..e251e32ca 100644 --- a/src/cmd/6l/asm.c +++ b/src/cmd/6l/asm.c @@ -44,49 +44,22 @@ char freebsddynld[] = "/libexec/ld-elf.so.1"; char openbsddynld[] = "/usr/libexec/ld.so"; char netbsddynld[] = "/libexec/ld.elf_so"; char dragonflydynld[] = "/usr/libexec/ld-elf.so.2"; +char solarisdynld[] = "/lib/amd64/ld.so.1"; char zeroes[32]; -vlong -entryvalue(void) -{ - char *a; - Sym *s; - - a = INITENTRY; - if(*a >= '0' && *a <= '9') - return atolwhex(a); - s = lookup(a, 0); - if(s->type == 0) - return INITTEXT; - if(s->type != STEXT) - diag("entry not text: %s", s->name); - return s->value; -} - -vlong -datoff(vlong addr) -{ - 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; -} - static int needlib(char *name) { char *p; - Sym *s; + LSym *s; if(*name == '\0') return 0; /* reuse hash code in symbol table */ p = smprint(".elfload.%s", name); - s = lookup(p, 0); + s = linklookup(ctxt, p, 0); free(p); if(s->type == 0) { s->type = 100; // avoid SDATA, etc. @@ -97,24 +70,24 @@ needlib(char *name) int nelfsym = 1; -static void addpltsym(Sym*); -static void addgotsym(Sym*); +static void addpltsym(LSym*); +static void addgotsym(LSym*); void -adddynrela(Sym *rela, Sym *s, Reloc *r) +adddynrela(LSym *rela, LSym *s, Reloc *r) { - addaddrplus(rela, s, r->off); - adduint64(rela, R_X86_64_RELATIVE); - addaddrplus(rela, r->sym, r->add); // Addend + addaddrplus(ctxt, rela, s, r->off); + adduint64(ctxt, rela, R_X86_64_RELATIVE); + addaddrplus(ctxt, rela, r->sym, r->add); // Addend } void -adddynrel(Sym *s, Reloc *r) +adddynrel(LSym *s, Reloc *r) { - Sym *targ, *rela, *got; + LSym *targ, *rela, *got; targ = r->sym; - cursym = s; + ctxt->cursym = s; switch(r->type) { default: @@ -130,16 +103,16 @@ adddynrel(Sym *s, Reloc *r) 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->type = R_PCREL; r->add += 4; return; case 256 + R_X86_64_PLT32: - r->type = D_PCREL; + r->type = R_PCREL; r->add += 4; if(targ->type == SDYNIMPORT) { addpltsym(targ); - r->sym = lookup(".plt", 0); + r->sym = linklookup(ctxt, ".plt", 0); r->add += targ->plt; } return; @@ -150,7 +123,7 @@ adddynrel(Sym *s, Reloc *r) if(r->off >= 2 && s->p[r->off-2] == 0x8b) { // turn MOVQ of GOT entry into LEAQ of symbol itself s->p[r->off-2] = 0x8d; - r->type = D_PCREL; + r->type = R_PCREL; r->add += 4; return; } @@ -158,8 +131,8 @@ adddynrel(Sym *s, Reloc *r) // TODO: just needs relocation, no need to put in .dynsym } addgotsym(targ); - r->type = D_PCREL; - r->sym = lookup(".got", 0); + r->type = R_PCREL; + r->sym = linklookup(ctxt, ".got", 0); r->add += 4; r->add += targ->got; return; @@ -167,7 +140,7 @@ adddynrel(Sym *s, Reloc *r) case 256 + R_X86_64_64: if(targ->type == SDYNIMPORT) diag("unexpected R_X86_64_64 relocation for dynamic symbol %s", targ->name); - r->type = D_ADDR; + r->type = R_ADDR; return; // Handle relocations found in Mach-O object files. @@ -175,7 +148,7 @@ adddynrel(Sym *s, Reloc *r) 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; + r->type = R_ADDR; if(targ->type == SDYNIMPORT) diag("unexpected reloc for dynamic symbol %s", targ->name); return; @@ -183,9 +156,9 @@ adddynrel(Sym *s, Reloc *r) case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 1: if(targ->type == SDYNIMPORT) { addpltsym(targ); - r->sym = lookup(".plt", 0); + r->sym = linklookup(ctxt, ".plt", 0); r->add = targ->plt; - r->type = D_PCREL; + r->type = R_PCREL; return; } // fall through @@ -194,7 +167,7 @@ adddynrel(Sym *s, Reloc *r) 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; + r->type = R_PCREL; if(targ->type == SDYNIMPORT) diag("unexpected pc-relative reloc for dynamic symbol %s", targ->name); return; @@ -208,7 +181,7 @@ adddynrel(Sym *s, Reloc *r) return; } s->p[r->off-2] = 0x8d; - r->type = D_PCREL; + r->type = R_PCREL; return; } // fall through @@ -216,8 +189,8 @@ adddynrel(Sym *s, Reloc *r) if(targ->type != SDYNIMPORT) diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name); addgotsym(targ); - r->type = D_PCREL; - r->sym = lookup(".got", 0); + r->type = R_PCREL; + r->sym = linklookup(ctxt, ".got", 0); r->add += targ->got; return; } @@ -227,24 +200,34 @@ adddynrel(Sym *s, Reloc *r) return; switch(r->type) { - case D_PCREL: + case R_CALL: + case R_PCREL: addpltsym(targ); - r->sym = lookup(".plt", 0); + r->sym = linklookup(ctxt, ".plt", 0); r->add = targ->plt; return; - case D_ADDR: + case R_ADDR: + if(s->type == STEXT && iself) { + // The code is asking for the address of an external + // function. We provide it with the address of the + // correspondent GOT symbol. + addgotsym(targ); + r->sym = linklookup(ctxt, ".got", 0); + r->add += targ->got; + return; + } if(s->type != SDATA) break; if(iself) { - adddynsym(targ); - rela = lookup(".rela", 0); - addaddrplus(rela, s, r->off); + adddynsym(ctxt, targ); + rela = linklookup(ctxt, ".rela", 0); + addaddrplus(ctxt, rela, s, r->off); if(r->siz == 8) - adduint64(rela, ELF64_R_INFO(targ->dynid, R_X86_64_64)); + adduint64(ctxt, 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); + adduint64(ctxt, rela, ELF64_R_INFO(targ->dynid, R_X86_64_32)); + adduint64(ctxt, rela, r->add); r->type = 256; // ignore during relocsym return; } @@ -259,22 +242,22 @@ adddynrel(Sym *s, Reloc *r) // 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); + adddynsym(ctxt, targ); + got = linklookup(ctxt, ".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); + adduint64(ctxt, got, 0); + adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), targ->dynid); r->type = 256; // ignore during relocsym return; } break; } - cursym = s; + ctxt->cursym = s; diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type); } @@ -290,7 +273,7 @@ elfreloc1(Reloc *r, vlong sectoff) default: return -1; - case D_ADDR: + case R_ADDR: if(r->siz == 4) VPUT(R_X86_64_32 | (uint64)elfsym<<32); else if(r->siz == 8) @@ -299,14 +282,25 @@ elfreloc1(Reloc *r, vlong sectoff) return -1; break; - case D_PCREL: + case R_TLS_LE: if(r->siz == 4) - VPUT(R_X86_64_PC32 | (uint64)elfsym<<32); + VPUT(R_X86_64_TPOFF32 | (uint64)elfsym<<32); else return -1; break; + + case R_CALL: + case R_PCREL: + if(r->siz == 4) { + if(r->xsym->type == SDYNIMPORT) + VPUT(R_X86_64_GOTPCREL | (uint64)elfsym<<32); + else + VPUT(R_X86_64_PC32 | (uint64)elfsym<<32); + } else + return -1; + break; - case D_TLS: + case R_TLS: if(r->siz == 4) { if(flag_shared) VPUT(R_X86_64_GOTTPOFF | (uint64)elfsym<<32); @@ -325,7 +319,7 @@ int machoreloc1(Reloc *r, vlong sectoff) { uint32 v; - Sym *rs; + LSym *rs; rs = r->xsym; @@ -347,10 +341,11 @@ machoreloc1(Reloc *r, vlong sectoff) switch(r->type) { default: return -1; - case D_ADDR: + case R_ADDR: v |= MACHO_X86_64_RELOC_UNSIGNED<<28; break; - case D_PCREL: + case R_CALL: + case R_PCREL: v |= 1<<24; // pc-relative bit v |= MACHO_X86_64_RELOC_BRANCH<<28; break; @@ -379,7 +374,7 @@ machoreloc1(Reloc *r, vlong sectoff) } int -archreloc(Reloc *r, Sym *s, vlong *val) +archreloc(Reloc *r, LSym *s, vlong *val) { USED(r); USED(s); @@ -390,68 +385,68 @@ archreloc(Reloc *r, Sym *s, vlong *val) void elfsetupplt(void) { - Sym *plt, *got; + LSym *plt, *got; - plt = lookup(".plt", 0); - got = lookup(".got.plt", 0); + plt = linklookup(ctxt, ".plt", 0); + got = linklookup(ctxt, ".got.plt", 0); if(plt->size == 0) { // pushq got+8(IP) - adduint8(plt, 0xff); - adduint8(plt, 0x35); - addpcrelplus(plt, got, 8); + adduint8(ctxt, plt, 0xff); + adduint8(ctxt, plt, 0x35); + addpcrelplus(ctxt, plt, got, 8); // jmpq got+16(IP) - adduint8(plt, 0xff); - adduint8(plt, 0x25); - addpcrelplus(plt, got, 16); + adduint8(ctxt, plt, 0xff); + adduint8(ctxt, plt, 0x25); + addpcrelplus(ctxt, plt, got, 16); // nopl 0(AX) - adduint32(plt, 0x00401f0f); + adduint32(ctxt, plt, 0x00401f0f); // assume got->size == 0 too - addaddrplus(got, lookup(".dynamic", 0), 0); - adduint64(got, 0); - adduint64(got, 0); + addaddrplus(ctxt, got, linklookup(ctxt, ".dynamic", 0), 0); + adduint64(ctxt, got, 0); + adduint64(ctxt, got, 0); } } static void -addpltsym(Sym *s) +addpltsym(LSym *s) { if(s->plt >= 0) return; - adddynsym(s); + adddynsym(ctxt, s); if(iself) { - Sym *plt, *got, *rela; + LSym *plt, *got, *rela; - plt = lookup(".plt", 0); - got = lookup(".got.plt", 0); - rela = lookup(".rela.plt", 0); + plt = linklookup(ctxt, ".plt", 0); + got = linklookup(ctxt, ".got.plt", 0); + rela = linklookup(ctxt, ".rela.plt", 0); if(plt->size == 0) elfsetupplt(); // jmpq *got+size(IP) - adduint8(plt, 0xff); - adduint8(plt, 0x25); - addpcrelplus(plt, got, got->size); + adduint8(ctxt, plt, 0xff); + adduint8(ctxt, plt, 0x25); + addpcrelplus(ctxt, plt, got, got->size); // add to got: pointer to current pos in plt - addaddrplus(got, plt, plt->size); + addaddrplus(ctxt, got, plt, plt->size); // pushq $x - adduint8(plt, 0x68); - adduint32(plt, (got->size-24-8)/8); + adduint8(ctxt, plt, 0x68); + adduint32(ctxt, plt, (got->size-24-8)/8); // jmpq .plt - adduint8(plt, 0xe9); - adduint32(plt, -(plt->size+4)); + adduint8(ctxt, plt, 0xe9); + adduint32(ctxt, 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); + addaddrplus(ctxt, rela, got, got->size-8); + adduint64(ctxt, rela, ELF64_R_INFO(s->dynid, R_X86_64_JMP_SLOT)); + adduint64(ctxt, rela, 0); s->plt = plt->size - 16; } else if(HEADTYPE == Hdarwin) { @@ -465,53 +460,53 @@ addpltsym(Sym *s) // http://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html // has details about what we're avoiding. - Sym *plt; + LSym *plt; addgotsym(s); - plt = lookup(".plt", 0); + plt = linklookup(ctxt, ".plt", 0); - adduint32(lookup(".linkedit.plt", 0), s->dynid); + adduint32(ctxt, linklookup(ctxt, ".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); + adduint8(ctxt, plt, 0xff); + adduint8(ctxt, plt, 0x25); + addpcrelplus(ctxt, plt, linklookup(ctxt, ".got", 0), s->got); } else { diag("addpltsym: unsupported binary format"); } } static void -addgotsym(Sym *s) +addgotsym(LSym *s) { - Sym *got, *rela; + LSym *got, *rela; if(s->got >= 0) return; - adddynsym(s); - got = lookup(".got", 0); + adddynsym(ctxt, s); + got = linklookup(ctxt, ".got", 0); s->got = got->size; - adduint64(got, 0); + adduint64(ctxt, 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); + rela = linklookup(ctxt, ".rela", 0); + addaddrplus(ctxt, rela, got, s->got); + adduint64(ctxt, rela, ELF64_R_INFO(s->dynid, R_X86_64_GLOB_DAT)); + adduint64(ctxt, rela, 0); } else if(HEADTYPE == Hdarwin) { - adduint32(lookup(".linkedit.got", 0), s->dynid); + adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), s->dynid); } else { diag("addgotsym: unsupported binary format"); } } void -adddynsym(Sym *s) +adddynsym(Link *ctxt, LSym *s) { - Sym *d; + LSym *d; int t; char *name; @@ -521,24 +516,24 @@ adddynsym(Sym *s) if(iself) { s->dynid = nelfsym++; - d = lookup(".dynsym", 0); + d = linklookup(ctxt, ".dynsym", 0); name = s->extname; - adduint32(d, addstring(lookup(".dynstr", 0), name)); + adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name)); /* type */ t = STB_GLOBAL << 4; if(s->cgoexport && (s->type&SMASK) == STEXT) t |= STT_FUNC; else t |= STT_OBJECT; - adduint8(d, t); + adduint8(ctxt, d, t); /* reserved */ - adduint8(d, 0); + adduint8(ctxt, d, 0); /* section where symbol is defined */ if(s->type == SDYNIMPORT) - adduint16(d, SHN_UNDEF); + adduint16(ctxt, d, SHN_UNDEF); else { switch(s->type) { default: @@ -555,21 +550,21 @@ adddynsym(Sym *s) t = 14; break; } - adduint16(d, t); + adduint16(ctxt, d, t); } /* value */ if(s->type == SDYNIMPORT) - adduint64(d, 0); + adduint64(ctxt, d, 0); else - addaddr(d, s); + addaddr(ctxt, d, s); /* size of object */ - adduint64(d, s->size); + adduint64(ctxt, d, s->size); if(!(s->cgoexport & CgoExportDynamic) && s->dynimplib && needlib(s->dynimplib)) { - elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, - addstring(lookup(".dynstr", 0), s->dynimplib)); + elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, + addstring(linklookup(ctxt, ".dynstr", 0), s->dynimplib)); } } else if(HEADTYPE == Hdarwin) { diag("adddynsym: missed symbol %s (%s)", s->name, s->extname); @@ -583,16 +578,16 @@ adddynsym(Sym *s) void adddynlib(char *lib) { - Sym *s; + LSym *s; if(!needlib(lib)) return; if(iself) { - s = lookup(".dynstr", 0); + s = linklookup(ctxt, ".dynstr", 0); if(s->size == 0) addstring(s, ""); - elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib)); + elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib)); } else if(HEADTYPE == Hdarwin) { machoadddynlib(lib); } else { @@ -607,7 +602,7 @@ asmb(void) int i; vlong vl, symo, dwarfoff, machlink; Section *sect; - Sym *sym; + LSym *sym; if(debug['v']) Bprint(&bso, "%5.2f asmb\n", cputime()); @@ -662,8 +657,7 @@ asmb(void) switch(HEADTYPE) { default: diag("unknown header type %d", HEADTYPE); - case Hplan9x32: - case Hplan9x64: + case Hplan9: case Helf: break; case Hdarwin: @@ -674,8 +668,10 @@ asmb(void) case Hnetbsd: case Hopenbsd: case Hdragonfly: + case Hsolaris: debug['8'] = 1; /* 64-bit addresses */ break; + case Hnacl: case Hwindows: break; } @@ -690,7 +686,7 @@ asmb(void) Bflush(&bso); switch(HEADTYPE) { default: - case Hplan9x64: + case Hplan9: case Helf: debug['s'] = 1; symo = HEADR+segtext.len+segdata.filelen; @@ -703,6 +699,8 @@ asmb(void) case Hnetbsd: case Hopenbsd: case Hdragonfly: + case Hsolaris: + case Hnacl: symo = rnd(HEADR+segtext.len, INITRND)+rnd(segrodata.len, INITRND)+segdata.filelen; symo = rnd(symo, INITRND); break; @@ -729,11 +727,11 @@ asmb(void) elfemitreloc(); } break; - case Hplan9x64: + case Hplan9: asmplan9sym(); cflush(); - sym = lookup("pclntab", 0); + sym = linklookup(ctxt, "pclntab", 0); if(sym != nil) { lcsize = sym->np; for(i=0; i < lcsize; i++) @@ -761,7 +759,7 @@ asmb(void) cseek(0L); switch(HEADTYPE) { default: - case Hplan9x64: /* plan9 */ + case Hplan9: /* plan9 */ magic = 4*26*26+7; magic |= 0x00008000; /* fat header */ lputb(magic); /* magic */ @@ -775,17 +773,6 @@ asmb(void) lputb(lcsize); /* line offsets */ vputb(vl); /* va of entry */ break; - case Hplan9x32: /* plan9 */ - magic = 4*26*26+7; - lputb(magic); /* magic */ - 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 Hdarwin: asmbmacho(); break; @@ -794,6 +781,8 @@ asmb(void) case Hnetbsd: case Hopenbsd: case Hdragonfly: + case Hsolaris: + case Hnacl: asmbelf(symo); break; case Hwindows: diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h index ecab867e4..7303910a6 100644 --- a/src/cmd/6l/l.h +++ b/src/cmd/6l/l.h @@ -31,6 +31,7 @@ #include #include #include +#include #include "6.out.h" #ifndef EXTERN @@ -40,8 +41,6 @@ enum { thechar = '6', - PtrSize = 8, - IntSize = 8, MaxAlign = 32, // max data alignment // Loop alignment constants: @@ -63,147 +62,13 @@ enum FuncAlign = 16 }; -#define P ((Prog*)0) -#define S ((Sym*)0) -#define TNAME (cursym?cursym->name:noname) - -typedef struct Adr Adr; -typedef struct Prog Prog; -typedef struct Sym Sym; -typedef struct Auto Auto; -typedef struct Optab Optab; -typedef struct Movtab Movtab; -typedef struct Reloc Reloc; - -struct Adr -{ - union - { - vlong u0offset; - char u0scon[8]; - Prog *u0cond; /* not used, but should be D_BRANCH */ - Ieee u0ieee; - char *u0sbig; - } u0; - Sym* sym; - short type; - char index; - char scale; -}; - -#define offset u0.u0offset -#define scon u0.u0scon -#define cond u0.u0cond -#define ieee u0.u0ieee -#define sbig u0.u0sbig - -struct Reloc -{ - int32 off; - uchar siz; - uchar done; - int32 type; - int64 add; - int64 xadd; - Sym* sym; - Sym* xsym; -}; - -struct Prog -{ - Adr from; - Adr to; - Prog* forwd; - Prog* comefrom; - Prog* link; - Prog* pcond; /* work on this */ - vlong pc; - int32 spadj; - int32 line; - short as; - char ft; /* oclass cache */ - char tt; - uchar mark; /* work on these */ - uchar back; - - char width; /* fake for DATA */ - char mode; /* 16, 32, or 64 */ -}; -#define datasize from.scale -#define textflag from.scale -#define iscall(p) ((p)->as == ACALL) - -struct Auto -{ - Sym* asym; - Auto* link; - int32 aoffset; - short type; - Sym* gotype; -}; -struct Sym -{ - char* name; - char* extname; // name used in external object files - short type; - short version; - uchar dupok; - uchar reachable; - uchar cgoexport; - uchar special; - uchar stkcheck; - uchar hide; - int32 dynid; - int32 sig; - int32 plt; - int32 got; - int32 align; // if non-zero, required alignment in bytes - int32 elfsym; - int32 args; // size of stack frame incoming arguments area - Sym* hash; // in hash table - Sym* allsym; // in all symbol list - Sym* next; // in text or data list - Sym* sub; // in SSUB list - Sym* outer; // container of sub - Sym* reachparent; - Sym* queue; - vlong value; - vlong size; - Sym* gotype; - char* file; - char* dynimplib; - char* dynimpvers; - struct Section* sect; - struct Hist* hist; // for ATEXT - - // STEXT - Auto* autom; - Prog* text; - - // SDATA, SBSS - uchar* p; - int32 np; - int32 maxp; - Reloc* r; - int32 nr; - int32 maxr; -}; -struct Optab -{ - short as; - uchar* ytab; - uchar prefix; - uchar op[23]; -}; -struct Movtab -{ - short as; - uchar ft; - uchar tt; - uchar code; - uchar op[4]; -}; +EXTERN int PtrSize; +EXTERN int IntSize; +EXTERN int RegSize; +#define P ((Prog*)0) +#define S ((LSym*)0) +#define TNAME (ctxt->cursym?ctxt->cursym->name:noname) enum { MINSIZ = 8, @@ -211,239 +76,42 @@ enum MINLC = 1, MAXIO = 8192, MAXHIST = 40, /* limit of path elements for history symbols */ - - Yxxx = 0, - Ynone, - Yi0, - Yi1, - Yi8, - Ys32, - Yi32, - Yi64, - Yiauto, - Yal, - Ycl, - Yax, - Ycx, - Yrb, - Yrl, - Yrf, - Yf0, - Yrx, - Ymb, - Yml, - Ym, - Ybr, - Ycol, - - Ycs, Yss, Yds, Yes, Yfs, Ygs, - Ygdtr, Yidtr, Yldtr, Ymsw, Ytask, - Ycr0, Ycr1, Ycr2, Ycr3, Ycr4, Ycr5, Ycr6, Ycr7, Ycr8, - Ydr0, Ydr1, Ydr2, Ydr3, Ydr4, Ydr5, Ydr6, Ydr7, - Ytr0, Ytr1, Ytr2, Ytr3, Ytr4, Ytr5, Ytr6, Ytr7, Yrl32, Yrl64, - Ymr, Ymm, - Yxr, Yxm, - Ymax, - - Zxxx = 0, - - Zlit, - Zlitm_r, - Z_rp, - Zbr, - Zcall, - Zib_, - Zib_rp, - Zibo_m, - Zibo_m_xm, - Zil_, - Zil_rp, - Ziq_rp, - Zilo_m, - Ziqo_m, - Zjmp, - Zloop, - Zo_iw, - Zm_o, - Zm_r, - Zm2_r, - Zm_r_xm, - Zm_r_i_xm, - Zm_r_3d, - Zm_r_xm_nr, - Zr_m_xm_nr, - Zibm_r, /* mmx1,mmx2/mem64,imm8 */ - Zmb_r, - Zaut_r, - Zo_m, - Zo_m64, - Zpseudo, - Zr_m, - Zr_m_xm, - Zr_m_i_xm, - Zrp_, - Z_ib, - Z_il, - Zm_ibo, - Zm_ilo, - Zib_rr, - Zil_rr, - Zclr, - Zbyte, - Zmax, - - Px = 0, - P32 = 0x32, /* 32-bit only */ - Pe = 0x66, /* operand escape */ - Pm = 0x0f, /* 2byte opcode escape */ - Pq = 0xff, /* both escapes: 66 0f */ - Pb = 0xfe, /* byte operands */ - Pf2 = 0xf2, /* xmm escape 1: f2 0f */ - Pf3 = 0xf3, /* xmm escape 2: f3 0f */ - Pq3 = 0x67, /* xmm escape 3: 66 48 0f */ - Pw = 0x48, /* Rex.w */ - Py = 0x80, /* defaults to 64-bit mode */ - - Rxf = 1<<9, /* internal flag for Rxr on from */ - Rxt = 1<<8, /* internal flag for Rxr on to */ - Rxw = 1<<3, /* =1, 64-bit operand size */ - Rxr = 1<<2, /* extend modrm reg */ - Rxx = 1<<1, /* extend sib index */ - Rxb = 1<<0, /* extend modrm r/m, sib base, or opcode reg */ - - Maxand = 10, /* in -a output width of the byte codes */ }; -#pragma varargck type "A" uint -#pragma varargck type "D" Adr* #pragma varargck type "I" uchar* -#pragma varargck type "P" Prog* -#pragma varargck type "R" int -#pragma varargck type "S" char* -#pragma varargck type "i" char* -EXTERN int32 HEADR; -EXTERN int32 HEADTYPE; -EXTERN int32 INITRND; -EXTERN int64 INITTEXT; -EXTERN int64 INITDAT; -EXTERN char* INITENTRY; /* entry point */ -EXTERN char* pcstr; -EXTERN Auto* curauto; -EXTERN Auto* curhist; -EXTERN Prog* curp; -EXTERN Sym* cursym; -EXTERN Sym* datap; +EXTERN LSym* datap; EXTERN int debug[128]; EXTERN char literal[32]; -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 int32 lcsize; -EXTERN int nerrors; -EXTERN char* noname; -EXTERN char* outfile; -EXTERN vlong pc; -EXTERN char* interpreter; EXTERN char* rpath; EXTERN int32 spsize; -EXTERN Sym* symlist; +EXTERN LSym* symlist; EXTERN int32 symsize; -EXTERN int tlsoffset; -EXTERN Prog zprg; -EXTERN int dtype; -EXTERN char* paramspace; -EXTERN Sym* adrgotype; // type symbol on last Adr read -EXTERN Sym* fromgotype; // type symbol on last p->from read EXTERN vlong textstksiz; EXTERN vlong textarg; -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*); +int Iconv(Fmt *fp); +void adddynlib(char *lib); +void adddynrel(LSym *s, Reloc *r); +void adddynrela(LSym *rela, LSym *s, Reloc *r); +void adddynsym(Link *ctxt, LSym *s); +int archreloc(Reloc *r, LSym *s, vlong *val); void asmb(void); -void asmdyn(void); -void asmins(Prog*); -void asmsym(void); -void asmelfsym(void); -vlong atolwhex(char*); -Prog* brchain(Prog*); -Prog* brloop(Prog*); -void buildop(void); -Prog* copyp(Prog*); -double cputime(void); -void datblk(int32, int32); -void deadcode(void); -void diag(char*, ...); -void dodata(void); -void doelf(void); -void domacho(void); -void doprof1(void); -void doprof2(void); -void dostkoff(void); -vlong entryvalue(void); -void follow(void); -void gethunk(void); -void gotypestrings(void); +int elfreloc1(Reloc *r, vlong sectoff); +void elfsetupplt(void); void listinit(void); -Sym* lookup(char*, int); -void lputb(int32); -void lputl(int32); -void instinit(void); -void main(int, char*[]); -void* mysbrk(uint32); -Prog* newtext(Prog*, Sym*); -void nopout(Prog*); -int opsize(Prog*); -void patch(void); -Prog* prg(void); -void parsetextconst(vlong); -int relinv(int); -vlong rnd(vlong, vlong); -void span(void); -void undef(void); -vlong symaddr(Sym*); -void vputb(uint64); -void vputl(uint64); -void wputb(uint16); -void wputl(uint16); -void xdefine(char*, int, vlong); - -void machseg(char*, vlong, vlong, vlong, vlong, uint32, uint32, uint32, uint32); -void machsymseg(uint32, uint32); -void machsect(char*, char*, vlong, vlong, uint32, uint32, uint32, uint32, uint32); -void machstack(vlong); -void machdylink(void); -uint32 machheadr(void); +int machoreloc1(Reloc *r, vlong sectoff); +void main(int argc, char *argv[]); +void parsetextconst(vlong arg); +vlong rnd(vlong v, vlong r); /* Native is little-endian */ #define LPUT(a) lputl(a) #define WPUT(a) wputl(a) #define VPUT(a) vputl(a) -#pragma varargck type "D" Adr* -#pragma varargck type "P" Prog* -#pragma varargck type "R" int -#pragma varargck type "Z" char* -#pragma varargck type "A" int -#pragma varargck argpos diag 1 - /* Used by ../ld/dwarf.c */ enum { diff --git a/src/cmd/6l/list.c b/src/cmd/6l/list.c index 5040e4327..d960fcc91 100644 --- a/src/cmd/6l/list.c +++ b/src/cmd/6l/list.c @@ -33,370 +33,13 @@ #include "l.h" #include "../ld/lib.h" -static Prog* bigP; - void listinit(void) { - - fmtinstall('R', Rconv); - fmtinstall('A', Aconv); - fmtinstall('D', Dconv); - fmtinstall('S', Sconv); - fmtinstall('P', Pconv); + listinit6(); fmtinstall('I', Iconv); } -int -Pconv(Fmt *fp) -{ - Prog *p; - - p = va_arg(fp->args, Prog*); - bigP = p; - switch(p->as) { - case ATEXT: - if(p->from.scale) { - fmtprint(fp, "(%d) %A %D,%d,%lD", - p->line, p->as, &p->from, p->from.scale, &p->to); - break; - } - fmtprint(fp, "(%d) %A %D,%lD", - p->line, p->as, &p->from, &p->to); - break; - default: - fmtprint(fp, "(%d) %A %D,%D", - p->line, p->as, &p->from, &p->to); - break; - case ADATA: - 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 0; -} - -int -Aconv(Fmt *fp) -{ - int i; - - i = va_arg(fp->args, int); - return fmtstrcpy(fp, anames[i]); -} - -int -Dconv(Fmt *fp) -{ - char str[STRINGSZ], s[STRINGSZ]; - Adr *a; - int i; - - a = va_arg(fp->args, Adr*); - i = a->type; - - if(fp->flags & FmtLong) { - if(i != D_CONST) { - // ATEXT dst is not constant - snprint(str, sizeof(str), "!!%D", a); - goto brk; - } - parsetextconst(a->offset); - if(textarg == 0) { - snprint(str, sizeof(str), "$%lld", textstksiz); - goto brk; - } - snprint(str, sizeof(str), "$%lld-%lld", textstksiz, textarg); - goto brk; - } - - if(i >= D_INDIR) { - if(a->offset) - snprint(str, sizeof(str), "%lld(%R)", a->offset, i-D_INDIR); - else - snprint(str, sizeof(str), "(%R)", i-D_INDIR); - goto brk; - } - switch(i) { - - default: - if(a->offset) - snprint(str, sizeof(str), "$%lld,%R", a->offset, i); - else - snprint(str, sizeof(str), "%R", i); - break; - - case D_NONE: - str[0] = 0; - break; - - case D_BRANCH: - if(bigP != P && bigP->pcond != P) - if(a->sym != S) - snprint(str, sizeof(str), "%llux+%s", bigP->pcond->pc, - a->sym->name); - else - snprint(str, sizeof(str), "%llux", bigP->pcond->pc); - else - snprint(str, sizeof(str), "%lld(PC)", a->offset); - break; - - case D_EXTERN: - if(a->sym) { - snprint(str, sizeof(str), "%s+%lld(SB)", a->sym->name, a->offset); - break; - } - snprint(str, sizeof(str), "!!noname!!+%lld(SB)", a->offset); - break; - - case D_STATIC: - if(a->sym) { - snprint(str, sizeof(str), "%s<%d>+%lld(SB)", a->sym->name, - a->sym->version, a->offset); - break; - } - snprint(str, sizeof(str), "!!noname!!<999>+%lld(SB)", a->offset); - break; - - case D_AUTO: - if(a->sym) { - snprint(str, sizeof(str), "%s+%lld(SP)", a->sym->name, a->offset); - break; - } - snprint(str, sizeof(str), "!!noname!!+%lld(SP)", a->offset); - break; - - case D_PARAM: - if(a->sym) { - snprint(str, sizeof(str), "%s+%lld(%s)", a->sym->name, a->offset, paramspace); - break; - } - snprint(str, sizeof(str), "!!noname!!+%lld(%s)", a->offset, paramspace); - break; - - case D_CONST: - snprint(str, sizeof(str), "$%lld", a->offset); - break; - - case D_FCONST: - snprint(str, sizeof(str), "$(%.8ux,%.8ux)", a->ieee.h, a->ieee.l); - break; - - case D_SCONST: - snprint(str, sizeof(str), "$\"%S\"", a->scon); - break; - - case D_ADDR: - a->type = a->index; - a->index = D_NONE; - snprint(str, sizeof(str), "$%D", a); - a->index = a->type; - a->type = D_ADDR; - goto conv; - } -brk: - if(a->index != D_NONE) { - snprint(s, sizeof(s), "(%R*%d)", a->index, a->scale); - strcat(str, s); - } -conv: - fmtstrcpy(fp, str); -// if(a->gotype) -// fmtprint(fp, "«%s»", a->gotype->name); - return 0; - -} - -char* regstr[] = -{ - "AL", /* [D_AL] */ - "CL", - "DL", - "BL", - "SPB", - "BPB", - "SIB", - "DIB", - "R8B", - "R9B", - "R10B", - "R11B", - "R12B", - "R13B", - "R14B", - "R15B", - - "AX", /* [D_AX] */ - "CX", - "DX", - "BX", - "SP", - "BP", - "SI", - "DI", - "R8", - "R9", - "R10", - "R11", - "R12", - "R13", - "R14", - "R15", - - "AH", - "CH", - "DH", - "BH", - - "F0", /* [D_F0] */ - "F1", - "F2", - "F3", - "F4", - "F5", - "F6", - "F7", - - "M0", - "M1", - "M2", - "M3", - "M4", - "M5", - "M6", - "M7", - - "X0", - "X1", - "X2", - "X3", - "X4", - "X5", - "X6", - "X7", - "X8", - "X9", - "X10", - "X11", - "X12", - "X13", - "X14", - "X15", - - "CS", /* [D_CS] */ - "SS", - "DS", - "ES", - "FS", - "GS", - - "GDTR", /* [D_GDTR] */ - "IDTR", /* [D_IDTR] */ - "LDTR", /* [D_LDTR] */ - "MSW", /* [D_MSW] */ - "TASK", /* [D_TASK] */ - - "CR0", /* [D_CR] */ - "CR1", - "CR2", - "CR3", - "CR4", - "CR5", - "CR6", - "CR7", - "CR8", - "CR9", - "CR10", - "CR11", - "CR12", - "CR13", - "CR14", - "CR15", - - "DR0", /* [D_DR] */ - "DR1", - "DR2", - "DR3", - "DR4", - "DR5", - "DR6", - "DR7", - - "TR0", /* [D_TR] */ - "TR1", - "TR2", - "TR3", - "TR4", - "TR5", - "TR6", - "TR7", - - "NONE", /* [D_NONE] */ -}; - -int -Rconv(Fmt *fp) -{ - char str[STRINGSZ]; - int r; - - r = va_arg(fp->args, int); - if(r >= D_AL && r <= D_NONE) - snprint(str, sizeof(str), "%s", regstr[r-D_AL]); - else - snprint(str, sizeof(str), "gok(%d)", r); - - return fmtstrcpy(fp, str); -} - -int -Sconv(Fmt *fp) -{ - int i, c; - char str[STRINGSZ], *p, *a; - - a = va_arg(fp->args, char*); - p = str; - for(i=0; i= 'a' && c <= 'z' || - c >= 'A' && c <= 'Z' || - c >= '0' && c <= '9') { - *p++ = c; - continue; - } - *p++ = '\\'; - switch(c) { - default: - if(c < 040 || c >= 0177) - break; /* not portable */ - p[-1] = c; - continue; - case 0: - *p++ = 'z'; - continue; - case '\\': - case '"': - *p++ = c; - continue; - case '\n': - *p++ = 'n'; - continue; - case '\t': - *p++ = 't'; - continue; - } - *p++ = (c>>6) + '0'; - *p++ = ((c>>3) & 7) + '0'; - *p++ = (c & 7) + '0'; - } - *p = 0; - return fmtstrcpy(fp, str); -} - int Iconv(Fmt *fp) { @@ -422,40 +65,3 @@ Iconv(Fmt *fp) free(s); return 0; } - -void -diag(char *fmt, ...) -{ - char buf[1024], *tn, *sep; - va_list arg; - - 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%s\n", tn, sep, buf); - - nerrors++; - if(nerrors > 20) { - print("too many errors\n"); - errorexit(); - } -} - -void -parsetextconst(vlong arg) -{ - textstksiz = arg & 0xffffffffLL; - if(textstksiz & 0x80000000LL) - textstksiz = -(-textstksiz & 0xffffffffLL); - - textarg = (arg >> 32) & 0xffffffffLL; - if(textarg & 0x80000000LL) - textarg = 0; - textarg = (textarg+7) & ~7LL; -} diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c index ae649a74b..3b8e8f4d7 100644 --- a/src/cmd/6l/obj.c +++ b/src/cmd/6l/obj.c @@ -30,7 +30,6 @@ // Reading object files. -#define EXTERN #include "l.h" #include "../ld/lib.h" #include "../ld/elf.h" @@ -39,104 +38,22 @@ #include "../ld/pe.h" #include -char *noname = ""; char* thestring = "amd64"; -char* paramspace = "FP"; - -Header headers[] = { - "plan9x32", Hplan9x32, - "plan9", Hplan9x64, - "elf", Helf, - "darwin", Hdarwin, - "dragonfly", Hdragonfly, - "linux", Hlinux, - "freebsd", Hfreebsd, - "netbsd", Hnetbsd, - "openbsd", Hopenbsd, - "windows", Hwindows, - "windowsgui", Hwindows, - 0, 0 -}; - -/* - * -Hplan9x32 -T4128 -R4096 is plan9 32-bit format - * -Hplan9 -T0x200028 -R0x200000 is plan9 64-bit format - * -Helf -T0x80110000 -R4096 is ELF32 - * -Hdarwin -Tx -Rx is apple MH-exec - * -Hdragonfly -Tx -Rx is DragonFly elf-exec - * -Hlinux -Tx -Rx is linux elf-exec - * -Hfreebsd -Tx -Rx is FreeBSD elf-exec - * -Hnetbsd -Tx -Rx is NetBSD elf-exec - * -Hopenbsd -Tx -Rx is OpenBSD elf-exec - * -Hwindows -Tx -Rx is MS Windows PE32+ - */ +LinkArch* thelinkarch = &linkamd64; void -main(int argc, char *argv[]) +linkarchinit(void) { - Binit(&bso, 1, OWRITE); - listinit(); - memset(debug, 0, sizeof(debug)); - nerrors = 0; - outfile = nil; - HEADTYPE = -1; - INITTEXT = -1; - INITDAT = -1; - INITRND = -1; - INITENTRY = 0; - linkmode = LinkAuto; - nuxiinit(); - - flagcount("1", "use alternate profiling code", &debug['1']); - flagcount("8", "assume 64-bit addresses", &debug['8']); - flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo); - flagint64("D", "addr: data address", &INITDAT); - flagstr("E", "sym: entry symbol", &INITENTRY); - flagfn1("I", "interp: set ELF interp", setinterp); - flagfn1("L", "dir: add dir to library path", Lflag); - flagfn1("H", "head: header type", setheadtype); - flagcount("K", "add stack underflow checks", &debug['K']); - flagcount("O", "print pc-line tables", &debug['O']); - flagcount("Q", "debug byte-register code gen", &debug['Q']); - flagint32("R", "rnd: address rounding", &INITRND); - flagcount("S", "check type signatures", &debug['S']); - flagint64("T", "addr: text address", &INITTEXT); - flagfn0("V", "print version and exit", doversion); - flagcount("W", "disassemble input", &debug['W']); - flagfn2("X", "name value: define string data", addstrdata); - flagcount("Z", "clear stack frame on entry", &debug['Z']); - flagcount("a", "disassemble output", &debug['a']); - flagcount("c", "dump call graph", &debug['c']); - flagcount("d", "disable dynamic executable", &debug['d']); - flagstr("extld", "linker to run in external mode", &extld); - flagstr("extldflags", "flags for external linker", &extldflags); - flagcount("f", "ignore version mismatch", &debug['f']); - flagcount("g", "disable go package data checks", &debug['g']); - flagstr("installsuffix", "pkg directory suffix", &flag_installsuffix); - flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode); - flagstr("k", "sym: set field tracking symbol", &tracksym); - flagcount("n", "dump symbol table", &debug['n']); - flagstr("o", "outfile: set output file", &outfile); - flagcount("p", "insert profiling code", &debug['p']); - flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath); - flagcount("race", "enable race detector", &flag_race); - flagcount("s", "disable symbol table", &debug['s']); - flagcount("shared", "generate shared object (implies -linkmode external)", &flag_shared); - flagstr("tmpdir", "leave temporary files in this directory", &tmpdir); - flagcount("u", "reject unsafe packages", &debug['u']); - flagcount("v", "print link trace", &debug['v']); - flagcount("w", "disable DWARF generation", &debug['w']); - - flagparse(&argc, &argv, usage); - - if(argc != 1) - usage(); - - mywhatsys(); // get goos - - if(HEADTYPE == -1) - HEADTYPE = headtype(goos); + if(strcmp(getgoarch(), "amd64p32") == 0) + thelinkarch = &linkamd64p32; + PtrSize = thelinkarch->ptrsize; + IntSize = PtrSize; + RegSize = thelinkarch->regsize; +} +void +archinit(void) +{ // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when // Go was built; see ../../make.bash. if(linkmode == LinkAuto && strcmp(getgoextlinkenabled(), "0") == 0) @@ -156,34 +73,18 @@ main(int argc, char *argv[]) case Hdragonfly: case Hfreebsd: case Hlinux: + case Hnacl: case Hnetbsd: case Hopenbsd: + case Hsolaris: break; } - if(outfile == nil) { - if(HEADTYPE == Hwindows) - outfile = "6.out.exe"; - else - outfile = "6.out"; - } - - libinit(); - switch(HEADTYPE) { default: diag("unknown -H option"); errorexit(); - case Hplan9x32: /* plan 9 */ - HEADR = 32L; - if(INITTEXT == -1) - INITTEXT = 4096+HEADR; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = 4096; - break; - case Hplan9x64: /* plan 9 */ + case Hplan9: /* plan 9 */ HEADR = 32L + 8L; if(INITTEXT == -1) INITTEXT = 0x200000+HEADR; @@ -202,11 +103,6 @@ main(int argc, char *argv[]) INITRND = 4096; break; case Hdarwin: /* apple MACH */ - /* - * OS X system constant - offset from 0(GS) to our TLS. - * Explained in ../../pkg/runtime/cgo/gcc_darwin_amd64.c. - */ - tlsoffset = 0x8a0; machoinit(); HEADR = INITIAL_MACHO_HEADR; if(INITRND == -1) @@ -221,13 +117,7 @@ main(int argc, char *argv[]) case Hnetbsd: /* netbsd */ case Hopenbsd: /* openbsd */ case Hdragonfly: /* dragonfly */ - /* - * ELF uses TLS offset negative from FS. - * Translate 0(FS) and 8(FS) into -16(FS) and -8(FS). - * Also known to ../../pkg/runtime/sys_linux_amd64.s - * and ../../pkg/runtime/cgo/gcc_linux_amd64.c. - */ - tlsoffset = -16; + case Hsolaris: /* solaris */ elfinit(); HEADR = ELFRESERVE; if(INITTEXT == -1) @@ -237,6 +127,18 @@ main(int argc, char *argv[]) if(INITRND == -1) INITRND = 4096; break; + case Hnacl: + elfinit(); + debug['w']++; // disable dwarf, which gets confused and is useless anyway + HEADR = 0x10000; + funcalign = 32; + if(INITTEXT == -1) + INITTEXT = 0x20000; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 0x10000; + break; case Hwindows: /* PE executable */ peinit(); HEADR = PEFILEHEADR; @@ -248,555 +150,8 @@ main(int argc, char *argv[]) INITRND = PESECTALIGN; break; } + if(INITDAT != 0 && INITRND != 0) print("warning: -D0x%llux is ignored because of -R0x%ux\n", INITDAT, INITRND); - if(debug['v']) - Bprint(&bso, "HEADER = -H%d -T0x%llux -D0x%llux -R0x%ux\n", - HEADTYPE, INITTEXT, INITDAT, INITRND); - Bflush(&bso); - instinit(); - - zprg.link = P; - zprg.pcond = P; - zprg.back = 2; - zprg.as = AGOK; - zprg.from.type = D_NONE; - zprg.from.index = D_NONE; - zprg.from.scale = 1; - zprg.to = zprg.from; - zprg.mode = 64; - - pcstr = "%.6llux "; - histgen = 0; - pc = 0; - dtype = 4; - version = 0; - cbp = buf.cbuf; - cbc = sizeof(buf.cbuf); - - addlibpath("command line", "command line", argv[0], "main"); - loadlib(); - deadcode(); - patch(); - follow(); - doelf(); - if(HEADTYPE == Hdarwin) - domacho(); - dostkoff(); - dostkcheck(); - paramspace = "SP"; /* (FP) now (SP) on output */ - if(debug['p']) - if(debug['1']) - doprof1(); - else - doprof2(); - span(); - if(HEADTYPE == Hwindows) - dope(); - addexport(); - textaddress(); - pclntab(); - symtab(); - dodata(); - address(); - doweak(); - reloc(); - asmb(); - undef(); - hostlink(); - if(debug['v']) { - Bprint(&bso, "%5.2f cpu time\n", cputime()); - Bprint(&bso, "%d symbols\n", nsymbol); - Bprint(&bso, "%d sizeof adr\n", sizeof(Adr)); - Bprint(&bso, "%d sizeof prog\n", sizeof(Prog)); - } - Bflush(&bso); - - errorexit(); -} - -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; - Sym *s; - Auto *u; - - t = BGETC(f); - a->index = D_NONE; - a->scale = 0; - if(t & T_INDEX) { - a->index = BGETC(f); - a->scale = BGETC(f); - } - a->offset = 0; - if(t & T_OFFSET) { - a->offset = BGETLE4(f); - if(t & T_64) { - a->offset &= 0xFFFFFFFFULL; - a->offset |= (uvlong)BGETLE4(f) << 32; - } - } - a->sym = S; - if(t & T_SYM) - a->sym = zsym(pn, f, h); - a->type = D_NONE; - if(t & T_FCONST) { - a->ieee.l = BGETLE4(f); - a->ieee.h = BGETLE4(f); - a->type = D_FCONST; - } else - if(t & T_SCONST) { - Bread(f, a->scon, NSNAME); - a->type = D_SCONST; - } - 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 = zsym(pn, f, h); - s = a->sym; - t = a->type; - if(t == D_INDIR+D_GS || a->index == D_GS) - a->offset += tlsoffset; - if(t != D_AUTO && t != D_PARAM) { - if(s && adrgotype) - s->gotype = adrgotype; - return; - } - l = a->offset; - for(u=curauto; u; u=u->link) { - if(u->asym == s) - if(u->type == t) { - if(u->aoffset > l) - u->aoffset = l; - if(adrgotype) - u->gotype = adrgotype; - return; - } - } - - switch(t) { - case D_FILE: - case D_FILE1: - case D_AUTO: - case D_PARAM: - if(s == S) - mangle(pn); - } - - u = mal(sizeof(*u)); - u->link = curauto; - curauto = u; - u->asym = s; - u->aoffset = l; - u->type = t; - u->gotype = adrgotype; -} - -void -nopout(Prog *p) -{ - p->as = ANOP; - p->from.type = D_NONE; - p->to.type = D_NONE; -} - -void -ldobj1(Biobuf *f, char *pkg, int64 len, char *pn) -{ - vlong ipc; - Prog *p; - int v, o, r, skip, mode; - Sym *h[NSYM], *s; - uint32 sig; - char *name, *x; - int ntext; - vlong eof; - char src[1024]; - Prog *lastp; - - lastp = nil; - ntext = 0; - eof = Boffset(f) + len; - src[0] = 0; - pn = estrdup(pn); // we keep it in Sym* references - -newloop: - memset(h, 0, sizeof(h)); - version++; - histfrogp = 0; - ipc = pc; - skip = 0; - mode = 64; - -loop: - if(f->state == Bracteof || Boffset(f) >= eof) - goto eof; - o = BGETC(f); - if(o == Beof) - goto eof; - o |= BGETC(f) << 8; - if(o <= AXXX || o >= ALAST) { - if(o < 0) - goto eof; - diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o); - print(" probably not a .6 file\n"); - errorexit(); - } - - if(o == ANAME || o == ASIGNAME) { - sig = 0; - if(o == ASIGNAME) - sig = BGETLE4(f); - v = BGETC(f); /* type */ - o = BGETC(f); /* sym */ - r = 0; - if(v == D_STATIC) - r = version; - name = Brdline(f, '\0'); - if(name == nil) { - if(Blinelen(f) > 0) { - fprint(2, "%s: name too long\n", pn); - errorexit(); - } - goto eof; - } - x = expandpkg(name, pkg); - s = lookup(x, r); - if(x != name) - free(x); - - if(debug['S'] && r == 0) - sig = 1729; - if(sig != 0){ - if(s->sig != 0 && s->sig != sig) - 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)) - mangle(pn); - h[o] = s; - if((v == D_EXTERN || v == D_STATIC) && s->type == 0) - s->type = SXREF; - if(v == D_FILE) { - if(s->type != SFILE) { - histgen++; - s->type = SFILE; - s->value = histgen; - } - if(histfrogp < MAXHIST) { - histfrog[histfrogp] = s; - histfrogp++; - } else - collapsefrog(s); - dwarfaddfrag(s->value, s->name); - } - goto loop; - } - - p = mal(sizeof(*p)); - p->as = o; - p->line = BGETLE4(f); - p->back = 2; - p->mode = mode; - zaddr(pn, f, &p->from, h); - fromgotype = adrgotype; - 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); - - switch(p->as) { - case AHISTORY: - if(p->to.offset == -1) { - addlib(src, pn); - histfrogp = 0; - goto loop; - } - if(src[0] == '\0') - copyhistfrog(src, sizeof src); - addhist(p->line, D_FILE); /* 'z' */ - if(p->to.offset) - addhist(p->to.offset, D_FILE1); /* 'Z' */ - savehist(p->line, p->to.offset); - histfrogp = 0; - goto loop; - - case AEND: - histtoauto(); - if(cursym != nil && cursym->text) - cursym->autom = curauto; - curauto = 0; - cursym = nil; - if(Boffset(f) == eof) - return; - goto newloop; - - case AGLOBL: - s = p->from.sym; - if(s->type == 0 || s->type == SXREF) { - s->type = SBSS; - s->size = 0; - } - if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) { - diag("%s: redefinition: %s in %s", - pn, s->name, TNAME); - s->type = SBSS; - s->size = 0; - } - 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; - else if(p->from.scale & NOPTR) - s->type = SNOPTRBSS; - goto loop; - - 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->dupok) { -// if(debug['v']) -// Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn); - goto loop; - } - 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(); - } - savedata(s, p, pn); - unmal(p, sizeof *p); - goto loop; - - case AGOK: - diag("%s: GOK opcode in %s", pn, TNAME); - pc++; - goto loop; - - case ATYPE: - if(skip) - goto casdef; - pc++; - goto loop; - - case ATEXT: - s = p->from.sym; - if(s->text != nil) { - if(p->from.scale & DUPOK) { - skip = 1; - goto casdef; - } - 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(cursym != nil && cursym->text) { - histtoauto(); - cursym->autom = curauto; - curauto = 0; - } - skip = 0; - 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; - goto casdef; - } - diag("%s: redefinition: %s\n%P", pn, s->name, p); - } - if(fromgotype) { - if(s->gotype && s->gotype != fromgotype) - diag("%s: type mismatch for %s", pn, s->name); - s->gotype = fromgotype; - } - s->type = STEXT; - s->hist = gethist(); - s->value = pc; - s->args = p->to.offset >> 32; - lastp = p; - p->pc = pc++; - goto loop; - - case AMODE: - if(p->from.type == D_CONST || p->from.type == D_INDIR+D_NONE){ - switch((int)p->from.offset){ - case 16: case 32: case 64: - mode = p->from.offset; - break; - } - } - goto loop; - - case AFMOVF: - case AFADDF: - case AFSUBF: - case AFSUBRF: - case AFMULF: - case AFDIVF: - case AFDIVRF: - case AFCOMF: - case AFCOMFP: - case AMOVSS: - case AADDSS: - case ASUBSS: - case AMULSS: - case ADIVSS: - case ACOMISS: - case AUCOMISS: - if(skip) - goto casdef; - if(p->from.type == D_FCONST) { - /* size sb 9 max */ - sprint(literal, "$%ux", ieeedtof(&p->from.ieee)); - s = lookup(literal, 0); - if(s->type == 0) { - s->type = SRODATA; - adduint32(s, ieeedtof(&p->from.ieee)); - s->reachable = 0; - } - p->from.type = D_EXTERN; - p->from.sym = s; - p->from.offset = 0; - } - goto casdef; - - case AFMOVD: - case AFADDD: - case AFSUBD: - case AFSUBRD: - case AFMULD: - case AFDIVD: - case AFDIVRD: - case AFCOMD: - case AFCOMDP: - case AMOVSD: - case AADDSD: - case ASUBSD: - case AMULSD: - case ADIVSD: - case ACOMISD: - case AUCOMISD: - if(skip) - goto casdef; - if(p->from.type == D_FCONST) { - /* size sb 18 max */ - sprint(literal, "$%ux.%ux", - p->from.ieee.l, p->from.ieee.h); - s = lookup(literal, 0); - if(s->type == 0) { - s->type = SRODATA; - adduint32(s, p->from.ieee.l); - adduint32(s, p->from.ieee.h); - s->reachable = 0; - } - p->from.type = D_EXTERN; - p->from.sym = s; - p->from.offset = 0; - } - goto casdef; - - casdef: - 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; - goto loop; - } - -eof: - diag("truncated object file: %s", pn); -} - -Prog* -prg(void) -{ - Prog *p; - - p = mal(sizeof(*p)); - - *p = zprg; - return p; -} - -Prog* -copyp(Prog *q) -{ - Prog *p; - - p = prg(); - *p = *q; - return p; -} - -Prog* -appendp(Prog *q) -{ - Prog *p; - - p = prg(); - p->link = q->link; - q->link = p; - p->line = q->line; - p->mode = q->mode; - return p; } diff --git a/src/cmd/6l/optab.c b/src/cmd/6l/optab.c deleted file mode 100644 index 46603ad45..000000000 --- a/src/cmd/6l/optab.c +++ /dev/null @@ -1,1369 +0,0 @@ -// Inferno utils/6l/optab.c -// http://code.google.com/p/inferno-os/source/browse/utils/6l/optab.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 "l.h" - -uchar ynone[] = -{ - Ynone, Ynone, Zlit, 1, - 0 -}; -uchar ytext[] = -{ - Ymb, Yi64, Zpseudo,1, - 0 -}; -uchar ynop[] = -{ - Ynone, Ynone, Zpseudo,0, - Ynone, Yiauto, Zpseudo,0, - Ynone, Yml, Zpseudo,0, - Ynone, Yrf, Zpseudo,0, - Ynone, Yxr, Zpseudo,0, - Yiauto, Ynone, Zpseudo,0, - Yml, Ynone, Zpseudo,0, - Yrf, Ynone, Zpseudo,0, - Yxr, Ynone, Zpseudo,1, - 0 -}; -uchar yfuncdata[] = -{ - Yi32, Ym, Zpseudo, 0, - 0 -}; -uchar ypcdata[] = -{ - Yi32, Yi32, Zpseudo, 0, - 0 -}; -uchar yxorb[] = -{ - Yi32, Yal, Zib_, 1, - Yi32, Ymb, Zibo_m, 2, - Yrb, Ymb, Zr_m, 1, - Ymb, Yrb, Zm_r, 1, - 0 -}; -uchar yxorl[] = -{ - Yi8, Yml, Zibo_m, 2, - Yi32, Yax, Zil_, 1, - Yi32, Yml, Zilo_m, 2, - Yrl, Yml, Zr_m, 1, - Yml, Yrl, Zm_r, 1, - 0 -}; -uchar yaddl[] = -{ - Yi8, Yml, Zibo_m, 2, - Yi32, Yax, Zil_, 1, - Yi32, Yml, Zilo_m, 2, - Yrl, Yml, Zr_m, 1, - Yml, Yrl, Zm_r, 1, - 0 -}; -uchar yincb[] = -{ - Ynone, Ymb, Zo_m, 2, - 0 -}; -uchar yincw[] = -{ - Ynone, Yml, Zo_m, 2, - 0 -}; -uchar yincl[] = -{ - Ynone, Yml, Zo_m, 2, - 0 -}; -uchar ycmpb[] = -{ - Yal, Yi32, Z_ib, 1, - Ymb, Yi32, Zm_ibo, 2, - Ymb, Yrb, Zm_r, 1, - Yrb, Ymb, Zr_m, 1, - 0 -}; -uchar ycmpl[] = -{ - Yml, Yi8, Zm_ibo, 2, - Yax, Yi32, Z_il, 1, - Yml, Yi32, Zm_ilo, 2, - Yml, Yrl, Zm_r, 1, - Yrl, Yml, Zr_m, 1, - 0 -}; -uchar yshb[] = -{ - Yi1, Ymb, Zo_m, 2, - Yi32, Ymb, Zibo_m, 2, - Ycx, Ymb, Zo_m, 2, - 0 -}; -uchar yshl[] = -{ - Yi1, Yml, Zo_m, 2, - Yi32, Yml, Zibo_m, 2, - Ycl, Yml, Zo_m, 2, - Ycx, Yml, Zo_m, 2, - 0 -}; -uchar ytestb[] = -{ - Yi32, Yal, Zib_, 1, - Yi32, Ymb, Zibo_m, 2, - Yrb, Ymb, Zr_m, 1, - Ymb, Yrb, Zm_r, 1, - 0 -}; -uchar ytestl[] = -{ - Yi32, Yax, Zil_, 1, - Yi32, Yml, Zilo_m, 2, - Yrl, Yml, Zr_m, 1, - Yml, Yrl, Zm_r, 1, - 0 -}; -uchar ymovb[] = -{ - Yrb, Ymb, Zr_m, 1, - Ymb, Yrb, Zm_r, 1, - Yi32, Yrb, Zib_rp, 1, - Yi32, Ymb, Zibo_m, 2, - 0 -}; -uchar ymbs[] = -{ - Ymb, Ynone, Zm_o, 2, - 0 -}; -uchar ybtl[] = -{ - Yi8, Yml, Zibo_m, 2, - Yrl, Yml, Zr_m, 1, - 0 -}; -uchar ymovw[] = -{ - Yrl, Yml, Zr_m, 1, - Yml, Yrl, Zm_r, 1, - Yi0, Yrl, Zclr, 1, - Yi32, Yrl, Zil_rp, 1, - Yi32, Yml, Zilo_m, 2, - Yiauto, Yrl, Zaut_r, 2, - 0 -}; -uchar ymovl[] = -{ - Yrl, Yml, Zr_m, 1, - Yml, Yrl, Zm_r, 1, - Yi0, Yrl, Zclr, 1, - Yi32, Yrl, Zil_rp, 1, - Yi32, Yml, Zilo_m, 2, - Yml, Ymr, Zm_r_xm, 1, // MMX MOVD - Ymr, Yml, Zr_m_xm, 1, // MMX MOVD - Yml, Yxr, Zm_r_xm, 2, // XMM MOVD (32 bit) - Yxr, Yml, Zr_m_xm, 2, // XMM MOVD (32 bit) - Yiauto, Yrl, Zaut_r, 2, - 0 -}; -uchar yret[] = -{ - Ynone, Ynone, Zo_iw, 1, - Yi32, Ynone, Zo_iw, 1, - 0 -}; -uchar ymovq[] = -{ - Yrl, Yml, Zr_m, 1, // 0x89 - Yml, Yrl, Zm_r, 1, // 0x8b - Yi0, Yrl, Zclr, 1, // 0x31 - Ys32, Yrl, Zilo_m, 2, // 32 bit signed 0xc7,(0) - Yi64, Yrl, Ziq_rp, 1, // 0xb8 -- 32/64 bit immediate - Yi32, Yml, Zilo_m, 2, // 0xc7,(0) - Ym, Ymr, Zm_r_xm_nr, 1, // MMX MOVQ (shorter encoding) - Ymr, Ym, Zr_m_xm_nr, 1, // MMX MOVQ - Ymm, Ymr, Zm_r_xm, 1, // MMX MOVD - Ymr, Ymm, Zr_m_xm, 1, // MMX MOVD - Yxr, Ymr, Zm_r_xm_nr, 2, // MOVDQ2Q - Yxm, Yxr, Zm_r_xm_nr, 2, // MOVQ xmm1/m64 -> xmm2 - Yxr, Yxm, Zr_m_xm_nr, 2, // MOVQ xmm1 -> xmm2/m64 - Yml, Yxr, Zm_r_xm, 2, // MOVD xmm load - Yxr, Yml, Zr_m_xm, 2, // MOVD xmm store - Yiauto, Yrl, Zaut_r, 2, // built-in LEAQ - 0 -}; -uchar ym_rl[] = -{ - Ym, Yrl, Zm_r, 1, - 0 -}; -uchar yrl_m[] = -{ - Yrl, Ym, Zr_m, 1, - 0 -}; -uchar ymb_rl[] = -{ - Ymb, Yrl, Zmb_r, 1, - 0 -}; -uchar yml_rl[] = -{ - Yml, Yrl, Zm_r, 1, - 0 -}; -uchar yrl_ml[] = -{ - Yrl, Yml, Zr_m, 1, - 0 -}; -uchar yml_mb[] = -{ - Yrb, Ymb, Zr_m, 1, - Ymb, Yrb, Zm_r, 1, - 0 -}; -uchar yrb_mb[] = -{ - Yrb, Ymb, Zr_m, 1, - 0 -}; -uchar yxchg[] = -{ - Yax, Yrl, Z_rp, 1, - Yrl, Yax, Zrp_, 1, - Yrl, Yml, Zr_m, 1, - Yml, Yrl, Zm_r, 1, - 0 -}; -uchar ydivl[] = -{ - Yml, Ynone, Zm_o, 2, - 0 -}; -uchar ydivb[] = -{ - Ymb, Ynone, Zm_o, 2, - 0 -}; -uchar yimul[] = -{ - Yml, Ynone, Zm_o, 2, - Yi8, Yrl, Zib_rr, 1, - Yi32, Yrl, Zil_rr, 1, - Yml, Yrl, Zm_r, 2, - 0 -}; -uchar yimul3[] = -{ - Yml, Yrl, Zibm_r, 2, - 0 -}; -uchar ybyte[] = -{ - Yi64, Ynone, Zbyte, 1, - 0 -}; -uchar yin[] = -{ - Yi32, Ynone, Zib_, 1, - Ynone, Ynone, Zlit, 1, - 0 -}; -uchar yint[] = -{ - Yi32, Ynone, Zib_, 1, - 0 -}; -uchar ypushl[] = -{ - Yrl, Ynone, Zrp_, 1, - Ym, Ynone, Zm_o, 2, - Yi8, Ynone, Zib_, 1, - Yi32, Ynone, Zil_, 1, - 0 -}; -uchar ypopl[] = -{ - Ynone, Yrl, Z_rp, 1, - Ynone, Ym, Zo_m, 2, - 0 -}; -uchar ybswap[] = -{ - Ynone, Yrl, Z_rp, 2, - 0, -}; -uchar yscond[] = -{ - Ynone, Ymb, Zo_m, 2, - 0 -}; -uchar yjcond[] = -{ - Ynone, Ybr, Zbr, 0, - Yi0, Ybr, Zbr, 0, - Yi1, Ybr, Zbr, 1, - 0 -}; -uchar yloop[] = -{ - Ynone, Ybr, Zloop, 1, - 0 -}; -uchar ycall[] = -{ - Ynone, Yml, Zo_m64, 0, - Yrx, Yrx, Zo_m64, 2, - Ynone, Ybr, Zcall, 1, - 0 -}; -uchar yjmp[] = -{ - Ynone, Yml, Zo_m64, 2, - Ynone, Ybr, Zjmp, 1, - 0 -}; - -uchar yfmvd[] = -{ - Ym, Yf0, Zm_o, 2, - Yf0, Ym, Zo_m, 2, - Yrf, Yf0, Zm_o, 2, - Yf0, Yrf, Zo_m, 2, - 0 -}; -uchar yfmvdp[] = -{ - Yf0, Ym, Zo_m, 2, - Yf0, Yrf, Zo_m, 2, - 0 -}; -uchar yfmvf[] = -{ - Ym, Yf0, Zm_o, 2, - Yf0, Ym, Zo_m, 2, - 0 -}; -uchar yfmvx[] = -{ - Ym, Yf0, Zm_o, 2, - 0 -}; -uchar yfmvp[] = -{ - Yf0, Ym, Zo_m, 2, - 0 -}; -uchar yfadd[] = -{ - Ym, Yf0, Zm_o, 2, - Yrf, Yf0, Zm_o, 2, - Yf0, Yrf, Zo_m, 2, - 0 -}; -uchar yfaddp[] = -{ - Yf0, Yrf, Zo_m, 2, - 0 -}; -uchar yfxch[] = -{ - Yf0, Yrf, Zo_m, 2, - Yrf, Yf0, Zm_o, 2, - 0 -}; -uchar ycompp[] = -{ - Yf0, Yrf, Zo_m, 2, /* botch is really f0,f1 */ - 0 -}; -uchar ystsw[] = -{ - Ynone, Ym, Zo_m, 2, - Ynone, Yax, Zlit, 1, - 0 -}; -uchar ystcw[] = -{ - Ynone, Ym, Zo_m, 2, - Ym, Ynone, Zm_o, 2, - 0 -}; -uchar ysvrs[] = -{ - Ynone, Ym, Zo_m, 2, - Ym, Ynone, Zm_o, 2, - 0 -}; -uchar ymm[] = -{ - Ymm, Ymr, Zm_r_xm, 1, - Yxm, Yxr, Zm_r_xm, 2, - 0 -}; -uchar yxm[] = -{ - Yxm, Yxr, Zm_r_xm, 1, - 0 -}; -uchar yxcvm1[] = -{ - Yxm, Yxr, Zm_r_xm, 2, - Yxm, Ymr, Zm_r_xm, 2, - 0 -}; -uchar yxcvm2[] = -{ - Yxm, Yxr, Zm_r_xm, 2, - Ymm, Yxr, Zm_r_xm, 2, - 0 -}; -uchar yxmq[] = -{ - Yxm, Yxr, Zm_r_xm, 2, - 0 -}; -uchar yxr[] = -{ - Yxr, Yxr, Zm_r_xm, 1, - 0 -}; -uchar yxr_ml[] = -{ - Yxr, Yml, Zr_m_xm, 1, - 0 -}; -uchar ymr[] = -{ - Ymr, Ymr, Zm_r, 1, - 0 -}; -uchar ymr_ml[] = -{ - Ymr, Yml, Zr_m_xm, 1, - 0 -}; -uchar yxcmp[] = -{ - Yxm, Yxr, Zm_r_xm, 1, - 0 -}; -uchar yxcmpi[] = -{ - Yxm, Yxr, Zm_r_i_xm, 2, - 0 -}; -uchar yxmov[] = -{ - Yxm, Yxr, Zm_r_xm, 1, - Yxr, Yxm, Zr_m_xm, 1, - 0 -}; -uchar yxcvfl[] = -{ - Yxm, Yrl, Zm_r_xm, 1, - 0 -}; -uchar yxcvlf[] = -{ - Yml, Yxr, Zm_r_xm, 1, - 0 -}; -uchar yxcvfq[] = -{ - Yxm, Yrl, Zm_r_xm, 2, - 0 -}; -uchar yxcvqf[] = -{ - Yml, Yxr, Zm_r_xm, 2, - 0 -}; -uchar yps[] = -{ - Ymm, Ymr, Zm_r_xm, 1, - Yi8, Ymr, Zibo_m_xm, 2, - Yxm, Yxr, Zm_r_xm, 2, - Yi8, Yxr, Zibo_m_xm, 3, - 0 -}; -uchar yxrrl[] = -{ - Yxr, Yrl, Zm_r, 1, - 0 -}; -uchar ymfp[] = -{ - Ymm, Ymr, Zm_r_3d, 1, - 0, -}; -uchar ymrxr[] = -{ - Ymr, Yxr, Zm_r, 1, - Yxm, Yxr, Zm_r_xm, 1, - 0 -}; -uchar ymshuf[] = -{ - Ymm, Ymr, Zibm_r, 2, - 0 -}; -uchar ymshufb[] = -{ - Yxm, Yxr, Zm2_r, 2, - 0 -}; -uchar yxshuf[] = -{ - Yxm, Yxr, Zibm_r, 2, - 0 -}; -uchar yextrw[] = -{ - Yxr, Yrl, Zibm_r, 2, - 0 -}; -uchar yinsrw[] = -{ - Yml, Yxr, Zibm_r, 2, - 0 -}; -uchar yinsr[] = -{ - Ymm, Yxr, Zibm_r, 3, - 0 -}; -uchar ypsdq[] = -{ - Yi8, Yxr, Zibo_m, 2, - 0 -}; -uchar ymskb[] = -{ - Yxr, Yrl, Zm_r_xm, 2, - Ymr, Yrl, Zm_r_xm, 1, - 0 -}; -uchar ycrc32l[] = -{ - Yml, Yrl, Zlitm_r, 0, -}; -uchar yprefetch[] = -{ - Ym, Ynone, Zm_o, 2, - 0, -}; -uchar yaes[] = -{ - Yxm, Yxr, Zlitm_r, 2, - 0 -}; -uchar yaes2[] = -{ - Yxm, Yxr, Zibm_r, 2, - 0 -}; - -/* - * You are doasm, holding in your hand a Prog* with p->as set to, say, ACRC32, - * and p->from and p->to as operands (Adr*). The linker scans optab to find - * the entry with the given p->as and then looks through the ytable for that - * instruction (the second field in the optab struct) for a line whose first - * two values match the Ytypes of the p->from and p->to operands. The function - * oclass in span.c computes the specific Ytype of an operand and then the set - * of more general Ytypes that it satisfies is implied by the ycover table, set - * up in instinit. For example, oclass distinguishes the constants 0 and 1 - * from the more general 8-bit constants, but instinit says - * - * ycover[Yi0*Ymax + Ys32] = 1; - * ycover[Yi1*Ymax + Ys32] = 1; - * ycover[Yi8*Ymax + Ys32] = 1; - * - * which means that Yi0, Yi1, and Yi8 all count as Ys32 (signed 32) - * if that's what an instruction can handle. - * - * In parallel with the scan through the ytable for the appropriate line, there - * is a z pointer that starts out pointing at the strange magic byte list in - * the Optab struct. With each step past a non-matching ytable line, z - * advances by the 4th entry in the line. When a matching line is found, that - * z pointer has the extra data to use in laying down the instruction bytes. - * The actual bytes laid down are a function of the 3rd entry in the line (that - * is, the Ztype) and the z bytes. - * - * For example, let's look at AADDL. The optab line says: - * { AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 }, - * - * and yaddl says - * uchar yaddl[] = - * { - * Yi8, Yml, Zibo_m, 2, - * Yi32, Yax, Zil_, 1, - * Yi32, Yml, Zilo_m, 2, - * Yrl, Yml, Zr_m, 1, - * Yml, Yrl, Zm_r, 1, - * 0 - * }; - * - * so there are 5 possible types of ADDL instruction that can be laid down, and - * possible states used to lay them down (Ztype and z pointer, assuming z - * points at {0x83,(00),0x05,0x81,(00),0x01,0x03}) are: - * - * Yi8, Yml -> Zibo_m, z (0x83, 00) - * Yi32, Yax -> Zil_, z+2 (0x05) - * Yi32, Yml -> Zilo_m, z+2+1 (0x81, 0x00) - * Yrl, Yml -> Zr_m, z+2+1+2 (0x01) - * Yml, Yrl -> Zm_r, z+2+1+2+1 (0x03) - * - * The Pconstant in the optab line controls the prefix bytes to emit. That's - * relatively straightforward as this program goes. - * - * The switch on t[2] in doasm implements the various Z cases. Zibo_m, for - * example, is an opcode byte (z[0]) then an asmando (which is some kind of - * encoded addressing mode for the Yml arg), and then a single immediate byte. - * Zilo_m is the same but a long (32-bit) immediate. - */ -Optab optab[] = -/* as, ytab, andproto, opcode */ -{ - { AXXX }, - { AAAA, ynone, P32, 0x37 }, - { AAAD, ynone, P32, 0xd5,0x0a }, - { AAAM, ynone, P32, 0xd4,0x0a }, - { AAAS, ynone, P32, 0x3f }, - { AADCB, yxorb, Pb, 0x14,0x80,(02),0x10,0x10 }, - { AADCL, yxorl, Px, 0x83,(02),0x15,0x81,(02),0x11,0x13 }, - { AADCQ, yxorl, Pw, 0x83,(02),0x15,0x81,(02),0x11,0x13 }, - { AADCW, yxorl, Pe, 0x83,(02),0x15,0x81,(02),0x11,0x13 }, - { AADDB, yxorb, Pb, 0x04,0x80,(00),0x00,0x02 }, - { AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 }, - { AADDPD, yxm, Pq, 0x58 }, - { AADDPS, yxm, Pm, 0x58 }, - { AADDQ, yaddl, Pw, 0x83,(00),0x05,0x81,(00),0x01,0x03 }, - { AADDSD, yxm, Pf2, 0x58 }, - { AADDSS, yxm, Pf3, 0x58 }, - { AADDW, yaddl, Pe, 0x83,(00),0x05,0x81,(00),0x01,0x03 }, - { AADJSP }, - { AANDB, yxorb, Pb, 0x24,0x80,(04),0x20,0x22 }, - { AANDL, yxorl, Px, 0x83,(04),0x25,0x81,(04),0x21,0x23 }, - { AANDNPD, yxm, Pq, 0x55 }, - { AANDNPS, yxm, Pm, 0x55 }, - { AANDPD, yxm, Pq, 0x54 }, - { AANDPS, yxm, Pq, 0x54 }, - { AANDQ, yxorl, Pw, 0x83,(04),0x25,0x81,(04),0x21,0x23 }, - { AANDW, yxorl, Pe, 0x83,(04),0x25,0x81,(04),0x21,0x23 }, - { AARPL, yrl_ml, P32, 0x63 }, - { ABOUNDL, yrl_m, P32, 0x62 }, - { ABOUNDW, yrl_m, Pe, 0x62 }, - { ABSFL, yml_rl, Pm, 0xbc }, - { ABSFQ, yml_rl, Pw, 0x0f,0xbc }, - { ABSFW, yml_rl, Pq, 0xbc }, - { ABSRL, yml_rl, Pm, 0xbd }, - { ABSRQ, yml_rl, Pw, 0x0f,0xbd }, - { ABSRW, yml_rl, Pq, 0xbd }, - { ABSWAPL, ybswap, Px, 0x0f,0xc8 }, - { ABSWAPQ, ybswap, Pw, 0x0f,0xc8 }, - { ABTCL, ybtl, Pm, 0xba,(07),0xbb }, - { ABTCQ, ybtl, Pw, 0x0f,0xba,(07),0x0f,0xbb }, - { ABTCW, ybtl, Pq, 0xba,(07),0xbb }, - { ABTL, ybtl, Pm, 0xba,(04),0xa3 }, - { ABTQ, ybtl, Pw, 0x0f,0xba,(04),0x0f,0xa3}, - { ABTRL, ybtl, Pm, 0xba,(06),0xb3 }, - { ABTRQ, ybtl, Pw, 0x0f,0xba,(06),0x0f,0xb3 }, - { ABTRW, ybtl, Pq, 0xba,(06),0xb3 }, - { ABTSL, ybtl, Pm, 0xba,(05),0xab }, - { ABTSQ, ybtl, Pw, 0x0f,0xba,(05),0x0f,0xab }, - { ABTSW, ybtl, Pq, 0xba,(05),0xab }, - { ABTW, ybtl, Pq, 0xba,(04),0xa3 }, - { ABYTE, ybyte, Px, 1 }, - { ACALL, ycall, Px, 0xff,(02),0xe8 }, - { ACDQ, ynone, Px, 0x99 }, - { ACLC, ynone, Px, 0xf8 }, - { ACLD, ynone, Px, 0xfc }, - { ACLI, ynone, Px, 0xfa }, - { ACLTS, ynone, Pm, 0x06 }, - { ACMC, ynone, Px, 0xf5 }, - { ACMOVLCC, yml_rl, Pm, 0x43 }, - { ACMOVLCS, yml_rl, Pm, 0x42 }, - { ACMOVLEQ, yml_rl, Pm, 0x44 }, - { ACMOVLGE, yml_rl, Pm, 0x4d }, - { ACMOVLGT, yml_rl, Pm, 0x4f }, - { ACMOVLHI, yml_rl, Pm, 0x47 }, - { ACMOVLLE, yml_rl, Pm, 0x4e }, - { ACMOVLLS, yml_rl, Pm, 0x46 }, - { ACMOVLLT, yml_rl, Pm, 0x4c }, - { ACMOVLMI, yml_rl, Pm, 0x48 }, - { ACMOVLNE, yml_rl, Pm, 0x45 }, - { ACMOVLOC, yml_rl, Pm, 0x41 }, - { ACMOVLOS, yml_rl, Pm, 0x40 }, - { ACMOVLPC, yml_rl, Pm, 0x4b }, - { ACMOVLPL, yml_rl, Pm, 0x49 }, - { ACMOVLPS, yml_rl, Pm, 0x4a }, - { ACMOVQCC, yml_rl, Pw, 0x0f,0x43 }, - { ACMOVQCS, yml_rl, Pw, 0x0f,0x42 }, - { ACMOVQEQ, yml_rl, Pw, 0x0f,0x44 }, - { ACMOVQGE, yml_rl, Pw, 0x0f,0x4d }, - { ACMOVQGT, yml_rl, Pw, 0x0f,0x4f }, - { ACMOVQHI, yml_rl, Pw, 0x0f,0x47 }, - { ACMOVQLE, yml_rl, Pw, 0x0f,0x4e }, - { ACMOVQLS, yml_rl, Pw, 0x0f,0x46 }, - { ACMOVQLT, yml_rl, Pw, 0x0f,0x4c }, - { ACMOVQMI, yml_rl, Pw, 0x0f,0x48 }, - { ACMOVQNE, yml_rl, Pw, 0x0f,0x45 }, - { ACMOVQOC, yml_rl, Pw, 0x0f,0x41 }, - { ACMOVQOS, yml_rl, Pw, 0x0f,0x40 }, - { ACMOVQPC, yml_rl, Pw, 0x0f,0x4b }, - { ACMOVQPL, yml_rl, Pw, 0x0f,0x49 }, - { ACMOVQPS, yml_rl, Pw, 0x0f,0x4a }, - { ACMOVWCC, yml_rl, Pq, 0x43 }, - { ACMOVWCS, yml_rl, Pq, 0x42 }, - { ACMOVWEQ, yml_rl, Pq, 0x44 }, - { ACMOVWGE, yml_rl, Pq, 0x4d }, - { ACMOVWGT, yml_rl, Pq, 0x4f }, - { ACMOVWHI, yml_rl, Pq, 0x47 }, - { ACMOVWLE, yml_rl, Pq, 0x4e }, - { ACMOVWLS, yml_rl, Pq, 0x46 }, - { ACMOVWLT, yml_rl, Pq, 0x4c }, - { ACMOVWMI, yml_rl, Pq, 0x48 }, - { ACMOVWNE, yml_rl, Pq, 0x45 }, - { ACMOVWOC, yml_rl, Pq, 0x41 }, - { ACMOVWOS, yml_rl, Pq, 0x40 }, - { ACMOVWPC, yml_rl, Pq, 0x4b }, - { ACMOVWPL, yml_rl, Pq, 0x49 }, - { ACMOVWPS, yml_rl, Pq, 0x4a }, - { ACMPB, ycmpb, Pb, 0x3c,0x80,(07),0x38,0x3a }, - { ACMPL, ycmpl, Px, 0x83,(07),0x3d,0x81,(07),0x39,0x3b }, - { ACMPPD, yxcmpi, Px, Pe,0xc2 }, - { ACMPPS, yxcmpi, Pm, 0xc2,0 }, - { ACMPQ, ycmpl, Pw, 0x83,(07),0x3d,0x81,(07),0x39,0x3b }, - { ACMPSB, ynone, Pb, 0xa6 }, - { ACMPSD, yxcmpi, Px, Pf2,0xc2 }, - { ACMPSL, ynone, Px, 0xa7 }, - { ACMPSQ, ynone, Pw, 0xa7 }, - { ACMPSS, yxcmpi, Px, Pf3,0xc2 }, - { ACMPSW, ynone, Pe, 0xa7 }, - { ACMPW, ycmpl, Pe, 0x83,(07),0x3d,0x81,(07),0x39,0x3b }, - { ACOMISD, yxcmp, Pe, 0x2f }, - { ACOMISS, yxcmp, Pm, 0x2f }, - { ACPUID, ynone, Pm, 0xa2 }, - { ACVTPL2PD, yxcvm2, Px, Pf3,0xe6,Pe,0x2a }, - { ACVTPL2PS, yxcvm2, Pm, 0x5b,0,0x2a,0, }, - { ACVTPD2PL, yxcvm1, Px, Pf2,0xe6,Pe,0x2d }, - { ACVTPD2PS, yxm, Pe, 0x5a }, - { ACVTPS2PL, yxcvm1, Px, Pe,0x5b,Pm,0x2d }, - { ACVTPS2PD, yxm, Pm, 0x5a }, - { API2FW, ymfp, Px, 0x0c }, - { ACVTSD2SL, yxcvfl, Pf2, 0x2d }, - { ACVTSD2SQ, yxcvfq, Pw, Pf2,0x2d }, - { ACVTSD2SS, yxm, Pf2, 0x5a }, - { ACVTSL2SD, yxcvlf, Pf2, 0x2a }, - { ACVTSQ2SD, yxcvqf, Pw, Pf2,0x2a }, - { ACVTSL2SS, yxcvlf, Pf3, 0x2a }, - { ACVTSQ2SS, yxcvqf, Pw, Pf3,0x2a }, - { ACVTSS2SD, yxm, Pf3, 0x5a }, - { ACVTSS2SL, yxcvfl, Pf3, 0x2d }, - { ACVTSS2SQ, yxcvfq, Pw, Pf3,0x2d }, - { ACVTTPD2PL, yxcvm1, Px, Pe,0xe6,Pe,0x2c }, - { ACVTTPS2PL, yxcvm1, Px, Pf3,0x5b,Pm,0x2c }, - { ACVTTSD2SL, yxcvfl, Pf2, 0x2c }, - { ACVTTSD2SQ, yxcvfq, Pw, Pf2,0x2c }, - { ACVTTSS2SL, yxcvfl, Pf3, 0x2c }, - { ACVTTSS2SQ, yxcvfq, Pw, Pf3,0x2c }, - { ACWD, ynone, Pe, 0x99 }, - { ACQO, ynone, Pw, 0x99 }, - { ADAA, ynone, P32, 0x27 }, - { ADAS, ynone, P32, 0x2f }, - { ADATA }, - { ADECB, yincb, Pb, 0xfe,(01) }, - { ADECL, yincl, Px, 0xff,(01) }, - { ADECQ, yincl, Pw, 0xff,(01) }, - { ADECW, yincw, Pe, 0xff,(01) }, - { ADIVB, ydivb, Pb, 0xf6,(06) }, - { ADIVL, ydivl, Px, 0xf7,(06) }, - { ADIVPD, yxm, Pe, 0x5e }, - { ADIVPS, yxm, Pm, 0x5e }, - { ADIVQ, ydivl, Pw, 0xf7,(06) }, - { ADIVSD, yxm, Pf2, 0x5e }, - { ADIVSS, yxm, Pf3, 0x5e }, - { ADIVW, ydivl, Pe, 0xf7,(06) }, - { AEMMS, ynone, Pm, 0x77 }, - { AENTER }, /* botch */ - { AFXRSTOR, ysvrs, Pm, 0xae,(01),0xae,(01) }, - { AFXSAVE, ysvrs, Pm, 0xae,(00),0xae,(00) }, - { AFXRSTOR64, ysvrs, Pw, 0x0f,0xae,(01),0x0f,0xae,(01) }, - { AFXSAVE64, ysvrs, Pw, 0x0f,0xae,(00),0x0f,0xae,(00) }, - { AGLOBL }, - { AGOK }, - { AHISTORY }, - { AHLT, ynone, Px, 0xf4 }, - { AIDIVB, ydivb, Pb, 0xf6,(07) }, - { AIDIVL, ydivl, Px, 0xf7,(07) }, - { AIDIVQ, ydivl, Pw, 0xf7,(07) }, - { AIDIVW, ydivl, Pe, 0xf7,(07) }, - { AIMULB, ydivb, Pb, 0xf6,(05) }, - { AIMULL, yimul, Px, 0xf7,(05),0x6b,0x69,Pm,0xaf }, - { AIMULQ, yimul, Pw, 0xf7,(05),0x6b,0x69,Pm,0xaf }, - { AIMULW, yimul, Pe, 0xf7,(05),0x6b,0x69,Pm,0xaf }, - { AIMUL3Q, yimul3, Pw, 0x6b,(00) }, - { AINB, yin, Pb, 0xe4,0xec }, - { AINCB, yincb, Pb, 0xfe,(00) }, - { AINCL, yincl, Px, 0xff,(00) }, - { AINCQ, yincl, Pw, 0xff,(00) }, - { AINCW, yincw, Pe, 0xff,(00) }, - { AINL, yin, Px, 0xe5,0xed }, - { AINSB, ynone, Pb, 0x6c }, - { AINSL, ynone, Px, 0x6d }, - { AINSW, ynone, Pe, 0x6d }, - { AINT, yint, Px, 0xcd }, - { AINTO, ynone, P32, 0xce }, - { AINW, yin, Pe, 0xe5,0xed }, - { AIRETL, ynone, Px, 0xcf }, - { AIRETQ, ynone, Pw, 0xcf }, - { AIRETW, ynone, Pe, 0xcf }, - { AJCC, yjcond, Px, 0x73,0x83,(00) }, - { AJCS, yjcond, Px, 0x72,0x82 }, - { AJCXZL, yloop, Px, 0xe3 }, - { AJCXZQ, yloop, Px, 0xe3 }, - { AJEQ, yjcond, Px, 0x74,0x84 }, - { AJGE, yjcond, Px, 0x7d,0x8d }, - { AJGT, yjcond, Px, 0x7f,0x8f }, - { AJHI, yjcond, Px, 0x77,0x87 }, - { AJLE, yjcond, Px, 0x7e,0x8e }, - { AJLS, yjcond, Px, 0x76,0x86 }, - { AJLT, yjcond, Px, 0x7c,0x8c }, - { AJMI, yjcond, Px, 0x78,0x88 }, - { AJMP, yjmp, Px, 0xff,(04),0xeb,0xe9 }, - { AJNE, yjcond, Px, 0x75,0x85 }, - { AJOC, yjcond, Px, 0x71,0x81,(00) }, - { AJOS, yjcond, Px, 0x70,0x80,(00) }, - { AJPC, yjcond, Px, 0x7b,0x8b }, - { AJPL, yjcond, Px, 0x79,0x89 }, - { AJPS, yjcond, Px, 0x7a,0x8a }, - { ALAHF, ynone, Px, 0x9f }, - { ALARL, yml_rl, Pm, 0x02 }, - { ALARW, yml_rl, Pq, 0x02 }, - { ALDMXCSR, ysvrs, Pm, 0xae,(02),0xae,(02) }, - { ALEAL, ym_rl, Px, 0x8d }, - { ALEAQ, ym_rl, Pw, 0x8d }, - { ALEAVEL, ynone, P32, 0xc9 }, - { ALEAVEQ, ynone, Py, 0xc9 }, - { ALEAVEW, ynone, Pe, 0xc9 }, - { ALEAW, ym_rl, Pe, 0x8d }, - { ALOCK, ynone, Px, 0xf0 }, - { ALODSB, ynone, Pb, 0xac }, - { ALODSL, ynone, Px, 0xad }, - { ALODSQ, ynone, Pw, 0xad }, - { ALODSW, ynone, Pe, 0xad }, - { ALONG, ybyte, Px, 4 }, - { ALOOP, yloop, Px, 0xe2 }, - { ALOOPEQ, yloop, Px, 0xe1 }, - { ALOOPNE, yloop, Px, 0xe0 }, - { ALSLL, yml_rl, Pm, 0x03 }, - { ALSLW, yml_rl, Pq, 0x03 }, - { AMASKMOVOU, yxr, Pe, 0xf7 }, - { AMASKMOVQ, ymr, Pm, 0xf7 }, - { AMAXPD, yxm, Pe, 0x5f }, - { AMAXPS, yxm, Pm, 0x5f }, - { AMAXSD, yxm, Pf2, 0x5f }, - { AMAXSS, yxm, Pf3, 0x5f }, - { AMINPD, yxm, Pe, 0x5d }, - { AMINPS, yxm, Pm, 0x5d }, - { AMINSD, yxm, Pf2, 0x5d }, - { AMINSS, yxm, Pf3, 0x5d }, - { AMOVAPD, yxmov, Pe, 0x28,0x29 }, - { AMOVAPS, yxmov, Pm, 0x28,0x29 }, - { AMOVB, ymovb, Pb, 0x88,0x8a,0xb0,0xc6,(00) }, - { AMOVBLSX, ymb_rl, Pm, 0xbe }, - { AMOVBLZX, ymb_rl, Pm, 0xb6 }, - { AMOVBQSX, ymb_rl, Pw, 0x0f,0xbe }, - { AMOVBQZX, ymb_rl, Pw, 0x0f,0xb6 }, - { AMOVBWSX, ymb_rl, Pq, 0xbe }, - { AMOVBWZX, ymb_rl, Pq, 0xb6 }, - { AMOVO, yxmov, Pe, 0x6f,0x7f }, - { AMOVOU, yxmov, Pf3, 0x6f,0x7f }, - { AMOVHLPS, yxr, Pm, 0x12 }, - { AMOVHPD, yxmov, Pe, 0x16,0x17 }, - { AMOVHPS, yxmov, Pm, 0x16,0x17 }, - { AMOVL, ymovl, Px, 0x89,0x8b,0x31,0xb8,0xc7,(00),0x6e,0x7e,Pe,0x6e,Pe,0x7e,0 }, - { AMOVLHPS, yxr, Pm, 0x16 }, - { AMOVLPD, yxmov, Pe, 0x12,0x13 }, - { AMOVLPS, yxmov, Pm, 0x12,0x13 }, - { AMOVLQSX, yml_rl, Pw, 0x63 }, - { AMOVLQZX, yml_rl, Px, 0x8b }, - { AMOVMSKPD, yxrrl, Pq, 0x50 }, - { AMOVMSKPS, yxrrl, Pm, 0x50 }, - { AMOVNTO, yxr_ml, Pe, 0xe7 }, - { AMOVNTPD, yxr_ml, Pe, 0x2b }, - { AMOVNTPS, yxr_ml, Pm, 0x2b }, - { AMOVNTQ, ymr_ml, Pm, 0xe7 }, - { AMOVQ, ymovq, Pw, 0x89, 0x8b, 0x31, 0xc7,(00), 0xb8, 0xc7,(00), 0x6f, 0x7f, 0x6e, 0x7e, Pf2,0xd6, Pf3,0x7e, Pe,0xd6, Pe,0x6e, Pe,0x7e,0 }, - { AMOVQOZX, ymrxr, Pf3, 0xd6,0x7e }, - { AMOVSB, ynone, Pb, 0xa4 }, - { AMOVSD, yxmov, Pf2, 0x10,0x11 }, - { AMOVSL, ynone, Px, 0xa5 }, - { AMOVSQ, ynone, Pw, 0xa5 }, - { AMOVSS, yxmov, Pf3, 0x10,0x11 }, - { AMOVSW, ynone, Pe, 0xa5 }, - { AMOVUPD, yxmov, Pe, 0x10,0x11 }, - { AMOVUPS, yxmov, Pm, 0x10,0x11 }, - { AMOVW, ymovw, Pe, 0x89,0x8b,0x31,0xb8,0xc7,(00),0 }, - { AMOVWLSX, yml_rl, Pm, 0xbf }, - { AMOVWLZX, yml_rl, Pm, 0xb7 }, - { AMOVWQSX, yml_rl, Pw, 0x0f,0xbf }, - { AMOVWQZX, yml_rl, Pw, 0x0f,0xb7 }, - { AMULB, ydivb, Pb, 0xf6,(04) }, - { AMULL, ydivl, Px, 0xf7,(04) }, - { AMULPD, yxm, Pe, 0x59 }, - { AMULPS, yxm, Ym, 0x59 }, - { AMULQ, ydivl, Pw, 0xf7,(04) }, - { AMULSD, yxm, Pf2, 0x59 }, - { AMULSS, yxm, Pf3, 0x59 }, - { AMULW, ydivl, Pe, 0xf7,(04) }, - { ANAME }, - { ANEGB, yscond, Pb, 0xf6,(03) }, - { ANEGL, yscond, Px, 0xf7,(03) }, - { ANEGQ, yscond, Pw, 0xf7,(03) }, - { ANEGW, yscond, Pe, 0xf7,(03) }, - { ANOP, ynop, Px, 0,0 }, - { ANOTB, yscond, Pb, 0xf6,(02) }, - { ANOTL, yscond, Px, 0xf7,(02) }, - { ANOTQ, yscond, Pw, 0xf7,(02) }, - { ANOTW, yscond, Pe, 0xf7,(02) }, - { AORB, yxorb, Pb, 0x0c,0x80,(01),0x08,0x0a }, - { AORL, yxorl, Px, 0x83,(01),0x0d,0x81,(01),0x09,0x0b }, - { AORPD, yxm, Pq, 0x56 }, - { AORPS, yxm, Pm, 0x56 }, - { AORQ, yxorl, Pw, 0x83,(01),0x0d,0x81,(01),0x09,0x0b }, - { AORW, yxorl, Pe, 0x83,(01),0x0d,0x81,(01),0x09,0x0b }, - { AOUTB, yin, Pb, 0xe6,0xee }, - { AOUTL, yin, Px, 0xe7,0xef }, - { AOUTSB, ynone, Pb, 0x6e }, - { AOUTSL, ynone, Px, 0x6f }, - { AOUTSW, ynone, Pe, 0x6f }, - { AOUTW, yin, Pe, 0xe7,0xef }, - { APACKSSLW, ymm, Py, 0x6b,Pe,0x6b }, - { APACKSSWB, ymm, Py, 0x63,Pe,0x63 }, - { APACKUSWB, ymm, Py, 0x67,Pe,0x67 }, - { APADDB, ymm, Py, 0xfc,Pe,0xfc }, - { APADDL, ymm, Py, 0xfe,Pe,0xfe }, - { APADDQ, yxm, Pe, 0xd4 }, - { APADDSB, ymm, Py, 0xec,Pe,0xec }, - { APADDSW, ymm, Py, 0xed,Pe,0xed }, - { APADDUSB, ymm, Py, 0xdc,Pe,0xdc }, - { APADDUSW, ymm, Py, 0xdd,Pe,0xdd }, - { APADDW, ymm, Py, 0xfd,Pe,0xfd }, - { APAND, ymm, Py, 0xdb,Pe,0xdb }, - { APANDN, ymm, Py, 0xdf,Pe,0xdf }, - { APAUSE, ynone, Px, 0xf3,0x90 }, - { APAVGB, ymm, Py, 0xe0,Pe,0xe0 }, - { APAVGW, ymm, Py, 0xe3,Pe,0xe3 }, - { APCMPEQB, ymm, Py, 0x74,Pe,0x74 }, - { APCMPEQL, ymm, Py, 0x76,Pe,0x76 }, - { APCMPEQW, ymm, Py, 0x75,Pe,0x75 }, - { APCMPGTB, ymm, Py, 0x64,Pe,0x64 }, - { APCMPGTL, ymm, Py, 0x66,Pe,0x66 }, - { APCMPGTW, ymm, Py, 0x65,Pe,0x65 }, - { APEXTRW, yextrw, Pq, 0xc5,(00) }, - { APF2IL, ymfp, Px, 0x1d }, - { APF2IW, ymfp, Px, 0x1c }, - { API2FL, ymfp, Px, 0x0d }, - { APFACC, ymfp, Px, 0xae }, - { APFADD, ymfp, Px, 0x9e }, - { APFCMPEQ, ymfp, Px, 0xb0 }, - { APFCMPGE, ymfp, Px, 0x90 }, - { APFCMPGT, ymfp, Px, 0xa0 }, - { APFMAX, ymfp, Px, 0xa4 }, - { APFMIN, ymfp, Px, 0x94 }, - { APFMUL, ymfp, Px, 0xb4 }, - { APFNACC, ymfp, Px, 0x8a }, - { APFPNACC, ymfp, Px, 0x8e }, - { APFRCP, ymfp, Px, 0x96 }, - { APFRCPIT1, ymfp, Px, 0xa6 }, - { APFRCPI2T, ymfp, Px, 0xb6 }, - { APFRSQIT1, ymfp, Px, 0xa7 }, - { APFRSQRT, ymfp, Px, 0x97 }, - { APFSUB, ymfp, Px, 0x9a }, - { APFSUBR, ymfp, Px, 0xaa }, - { APINSRW, yinsrw, Pq, 0xc4,(00) }, - { APINSRD, yinsr, Pq, 0x3a, 0x22, (00) }, - { APINSRQ, yinsr, Pq3, 0x3a, 0x22, (00) }, - { APMADDWL, ymm, Py, 0xf5,Pe,0xf5 }, - { APMAXSW, yxm, Pe, 0xee }, - { APMAXUB, yxm, Pe, 0xde }, - { APMINSW, yxm, Pe, 0xea }, - { APMINUB, yxm, Pe, 0xda }, - { APMOVMSKB, ymskb, Px, Pe,0xd7,0xd7 }, - { APMULHRW, ymfp, Px, 0xb7 }, - { APMULHUW, ymm, Py, 0xe4,Pe,0xe4 }, - { APMULHW, ymm, Py, 0xe5,Pe,0xe5 }, - { APMULLW, ymm, Py, 0xd5,Pe,0xd5 }, - { APMULULQ, ymm, Py, 0xf4,Pe,0xf4 }, - { APOPAL, ynone, P32, 0x61 }, - { APOPAW, ynone, Pe, 0x61 }, - { APOPFL, ynone, P32, 0x9d }, - { APOPFQ, ynone, Py, 0x9d }, - { APOPFW, ynone, Pe, 0x9d }, - { APOPL, ypopl, P32, 0x58,0x8f,(00) }, - { APOPQ, ypopl, Py, 0x58,0x8f,(00) }, - { APOPW, ypopl, Pe, 0x58,0x8f,(00) }, - { APOR, ymm, Py, 0xeb,Pe,0xeb }, - { APSADBW, yxm, Pq, 0xf6 }, - { APSHUFHW, yxshuf, Pf3, 0x70,(00) }, - { APSHUFL, yxshuf, Pq, 0x70,(00) }, - { APSHUFLW, yxshuf, Pf2, 0x70,(00) }, - { APSHUFW, ymshuf, Pm, 0x70,(00) }, - { APSHUFB, ymshufb,Pq, 0x38, 0x00 }, - { APSLLO, ypsdq, Pq, 0x73,(07) }, - { APSLLL, yps, Py, 0xf2, 0x72,(06), Pe,0xf2, Pe,0x72,(06) }, - { APSLLQ, yps, Py, 0xf3, 0x73,(06), Pe,0xf3, Pe,0x73,(06) }, - { APSLLW, yps, Py, 0xf1, 0x71,(06), Pe,0xf1, Pe,0x71,(06) }, - { APSRAL, yps, Py, 0xe2, 0x72,(04), Pe,0xe2, Pe,0x72,(04) }, - { APSRAW, yps, Py, 0xe1, 0x71,(04), Pe,0xe1, Pe,0x71,(04) }, - { APSRLO, ypsdq, Pq, 0x73,(03) }, - { APSRLL, yps, Py, 0xd2, 0x72,(02), Pe,0xd2, Pe,0x72,(02) }, - { APSRLQ, yps, Py, 0xd3, 0x73,(02), Pe,0xd3, Pe,0x73,(02) }, - { APSRLW, yps, Py, 0xd1, 0x71,(02), Pe,0xe1, Pe,0x71,(02) }, - { APSUBB, yxm, Pe, 0xf8 }, - { APSUBL, yxm, Pe, 0xfa }, - { APSUBQ, yxm, Pe, 0xfb }, - { APSUBSB, yxm, Pe, 0xe8 }, - { APSUBSW, yxm, Pe, 0xe9 }, - { APSUBUSB, yxm, Pe, 0xd8 }, - { APSUBUSW, yxm, Pe, 0xd9 }, - { APSUBW, yxm, Pe, 0xf9 }, - { APSWAPL, ymfp, Px, 0xbb }, - { APUNPCKHBW, ymm, Py, 0x68,Pe,0x68 }, - { APUNPCKHLQ, ymm, Py, 0x6a,Pe,0x6a }, - { APUNPCKHQDQ, yxm, Pe, 0x6d }, - { APUNPCKHWL, ymm, Py, 0x69,Pe,0x69 }, - { APUNPCKLBW, ymm, Py, 0x60,Pe,0x60 }, - { APUNPCKLLQ, ymm, Py, 0x62,Pe,0x62 }, - { APUNPCKLQDQ, yxm, Pe, 0x6c }, - { APUNPCKLWL, ymm, Py, 0x61,Pe,0x61 }, - { APUSHAL, ynone, P32, 0x60 }, - { APUSHAW, ynone, Pe, 0x60 }, - { APUSHFL, ynone, P32, 0x9c }, - { APUSHFQ, ynone, Py, 0x9c }, - { APUSHFW, ynone, Pe, 0x9c }, - { APUSHL, ypushl, P32, 0x50,0xff,(06),0x6a,0x68 }, - { APUSHQ, ypushl, Py, 0x50,0xff,(06),0x6a,0x68 }, - { APUSHW, ypushl, Pe, 0x50,0xff,(06),0x6a,0x68 }, - { APXOR, ymm, Py, 0xef,Pe,0xef }, - { AQUAD, ybyte, Px, 8 }, - { ARCLB, yshb, Pb, 0xd0,(02),0xc0,(02),0xd2,(02) }, - { ARCLL, yshl, Px, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) }, - { ARCLQ, yshl, Pw, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) }, - { ARCLW, yshl, Pe, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) }, - { ARCPPS, yxm, Pm, 0x53 }, - { ARCPSS, yxm, Pf3, 0x53 }, - { ARCRB, yshb, Pb, 0xd0,(03),0xc0,(03),0xd2,(03) }, - { ARCRL, yshl, Px, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) }, - { ARCRQ, yshl, Pw, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) }, - { ARCRW, yshl, Pe, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) }, - { AREP, ynone, Px, 0xf3 }, - { AREPN, ynone, Px, 0xf2 }, - { ARET, ynone, Px, 0xc3 }, - { ARETFW, yret, Pe, 0xcb,0xca }, - { ARETFL, yret, Px, 0xcb,0xca }, - { ARETFQ, yret, Pw, 0xcb,0xca }, - { AROLB, yshb, Pb, 0xd0,(00),0xc0,(00),0xd2,(00) }, - { AROLL, yshl, Px, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) }, - { AROLQ, yshl, Pw, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) }, - { AROLW, yshl, Pe, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) }, - { ARORB, yshb, Pb, 0xd0,(01),0xc0,(01),0xd2,(01) }, - { ARORL, yshl, Px, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) }, - { ARORQ, yshl, Pw, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) }, - { ARORW, yshl, Pe, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) }, - { ARSQRTPS, yxm, Pm, 0x52 }, - { ARSQRTSS, yxm, Pf3, 0x52 }, - { ASAHF, ynone, Px, 0x86,0xe0,0x50,0x9d }, /* XCHGB AH,AL; PUSH AX; POPFL */ - { ASALB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) }, - { ASALL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, - { ASALQ, yshl, Pw, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, - { ASALW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, - { ASARB, yshb, Pb, 0xd0,(07),0xc0,(07),0xd2,(07) }, - { ASARL, yshl, Px, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) }, - { ASARQ, yshl, Pw, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) }, - { ASARW, yshl, Pe, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) }, - { ASBBB, yxorb, Pb, 0x1c,0x80,(03),0x18,0x1a }, - { ASBBL, yxorl, Px, 0x83,(03),0x1d,0x81,(03),0x19,0x1b }, - { ASBBQ, yxorl, Pw, 0x83,(03),0x1d,0x81,(03),0x19,0x1b }, - { ASBBW, yxorl, Pe, 0x83,(03),0x1d,0x81,(03),0x19,0x1b }, - { ASCASB, ynone, Pb, 0xae }, - { ASCASL, ynone, Px, 0xaf }, - { ASCASQ, ynone, Pw, 0xaf }, - { ASCASW, ynone, Pe, 0xaf }, - { ASETCC, yscond, Pm, 0x93,(00) }, - { ASETCS, yscond, Pm, 0x92,(00) }, - { ASETEQ, yscond, Pm, 0x94,(00) }, - { ASETGE, yscond, Pm, 0x9d,(00) }, - { ASETGT, yscond, Pm, 0x9f,(00) }, - { ASETHI, yscond, Pm, 0x97,(00) }, - { ASETLE, yscond, Pm, 0x9e,(00) }, - { ASETLS, yscond, Pm, 0x96,(00) }, - { ASETLT, yscond, Pm, 0x9c,(00) }, - { ASETMI, yscond, Pm, 0x98,(00) }, - { ASETNE, yscond, Pm, 0x95,(00) }, - { ASETOC, yscond, Pm, 0x91,(00) }, - { ASETOS, yscond, Pm, 0x90,(00) }, - { ASETPC, yscond, Pm, 0x96,(00) }, - { ASETPL, yscond, Pm, 0x99,(00) }, - { ASETPS, yscond, Pm, 0x9a,(00) }, - { ASHLB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) }, - { ASHLL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, - { ASHLQ, yshl, Pw, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, - { ASHLW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, - { ASHRB, yshb, Pb, 0xd0,(05),0xc0,(05),0xd2,(05) }, - { ASHRL, yshl, Px, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) }, - { ASHRQ, yshl, Pw, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) }, - { ASHRW, yshl, Pe, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) }, - { ASHUFPD, yxshuf, Pq, 0xc6,(00) }, - { ASHUFPS, yxshuf, Pm, 0xc6,(00) }, - { ASQRTPD, yxm, Pe, 0x51 }, - { ASQRTPS, yxm, Pm, 0x51 }, - { ASQRTSD, yxm, Pf2, 0x51 }, - { ASQRTSS, yxm, Pf3, 0x51 }, - { ASTC, ynone, Px, 0xf9 }, - { ASTD, ynone, Px, 0xfd }, - { ASTI, ynone, Px, 0xfb }, - { ASTMXCSR, ysvrs, Pm, 0xae,(03),0xae,(03) }, - { ASTOSB, ynone, Pb, 0xaa }, - { ASTOSL, ynone, Px, 0xab }, - { ASTOSQ, ynone, Pw, 0xab }, - { ASTOSW, ynone, Pe, 0xab }, - { ASUBB, yxorb, Pb, 0x2c,0x80,(05),0x28,0x2a }, - { ASUBL, yaddl, Px, 0x83,(05),0x2d,0x81,(05),0x29,0x2b }, - { ASUBPD, yxm, Pe, 0x5c }, - { ASUBPS, yxm, Pm, 0x5c }, - { ASUBQ, yaddl, Pw, 0x83,(05),0x2d,0x81,(05),0x29,0x2b }, - { ASUBSD, yxm, Pf2, 0x5c }, - { ASUBSS, yxm, Pf3, 0x5c }, - { ASUBW, yaddl, Pe, 0x83,(05),0x2d,0x81,(05),0x29,0x2b }, - { ASWAPGS, ynone, Pm, 0x01,0xf8 }, - { ASYSCALL, ynone, Px, 0x0f,0x05 }, /* fast syscall */ - { ATESTB, ytestb, Pb, 0xa8,0xf6,(00),0x84,0x84 }, - { ATESTL, ytestl, Px, 0xa9,0xf7,(00),0x85,0x85 }, - { ATESTQ, ytestl, Pw, 0xa9,0xf7,(00),0x85,0x85 }, - { ATESTW, ytestl, Pe, 0xa9,0xf7,(00),0x85,0x85 }, - { ATEXT, ytext, Px }, - { AUCOMISD, yxcmp, Pe, 0x2e }, - { AUCOMISS, yxcmp, Pm, 0x2e }, - { AUNPCKHPD, yxm, Pe, 0x15 }, - { AUNPCKHPS, yxm, Pm, 0x15 }, - { AUNPCKLPD, yxm, Pe, 0x14 }, - { AUNPCKLPS, yxm, Pm, 0x14 }, - { AVERR, ydivl, Pm, 0x00,(04) }, - { AVERW, ydivl, Pm, 0x00,(05) }, - { AWAIT, ynone, Px, 0x9b }, - { AWORD, ybyte, Px, 2 }, - { AXCHGB, yml_mb, Pb, 0x86,0x86 }, - { AXCHGL, yxchg, Px, 0x90,0x90,0x87,0x87 }, - { AXCHGQ, yxchg, Pw, 0x90,0x90,0x87,0x87 }, - { AXCHGW, yxchg, Pe, 0x90,0x90,0x87,0x87 }, - { AXLAT, ynone, Px, 0xd7 }, - { AXORB, yxorb, Pb, 0x34,0x80,(06),0x30,0x32 }, - { AXORL, yxorl, Px, 0x83,(06),0x35,0x81,(06),0x31,0x33 }, - { AXORPD, yxm, Pe, 0x57 }, - { AXORPS, yxm, Pm, 0x57 }, - { AXORQ, yxorl, Pw, 0x83,(06),0x35,0x81,(06),0x31,0x33 }, - { AXORW, yxorl, Pe, 0x83,(06),0x35,0x81,(06),0x31,0x33 }, - - { AFMOVB, yfmvx, Px, 0xdf,(04) }, - { AFMOVBP, yfmvp, Px, 0xdf,(06) }, - { AFMOVD, yfmvd, Px, 0xdd,(00),0xdd,(02),0xd9,(00),0xdd,(02) }, - { AFMOVDP, yfmvdp, Px, 0xdd,(03),0xdd,(03) }, - { AFMOVF, yfmvf, Px, 0xd9,(00),0xd9,(02) }, - { AFMOVFP, yfmvp, Px, 0xd9,(03) }, - { AFMOVL, yfmvf, Px, 0xdb,(00),0xdb,(02) }, - { AFMOVLP, yfmvp, Px, 0xdb,(03) }, - { AFMOVV, yfmvx, Px, 0xdf,(05) }, - { AFMOVVP, yfmvp, Px, 0xdf,(07) }, - { AFMOVW, yfmvf, Px, 0xdf,(00),0xdf,(02) }, - { AFMOVWP, yfmvp, Px, 0xdf,(03) }, - { AFMOVX, yfmvx, Px, 0xdb,(05) }, - { AFMOVXP, yfmvp, Px, 0xdb,(07) }, - - { AFCOMB }, - { AFCOMBP }, - { AFCOMD, yfadd, Px, 0xdc,(02),0xd8,(02),0xdc,(02) }, /* botch */ - { AFCOMDP, yfadd, Px, 0xdc,(03),0xd8,(03),0xdc,(03) }, /* botch */ - { AFCOMDPP, ycompp, Px, 0xde,(03) }, - { AFCOMF, yfmvx, Px, 0xd8,(02) }, - { AFCOMFP, yfmvx, Px, 0xd8,(03) }, - { AFCOML, yfmvx, Px, 0xda,(02) }, - { AFCOMLP, yfmvx, Px, 0xda,(03) }, - { AFCOMW, yfmvx, Px, 0xde,(02) }, - { AFCOMWP, yfmvx, Px, 0xde,(03) }, - - { AFUCOM, ycompp, Px, 0xdd,(04) }, - { AFUCOMP, ycompp, Px, 0xdd,(05) }, - { AFUCOMPP, ycompp, Px, 0xda,(13) }, - - { AFADDDP, yfaddp, Px, 0xde,(00) }, - { AFADDW, yfmvx, Px, 0xde,(00) }, - { AFADDL, yfmvx, Px, 0xda,(00) }, - { AFADDF, yfmvx, Px, 0xd8,(00) }, - { AFADDD, yfadd, Px, 0xdc,(00),0xd8,(00),0xdc,(00) }, - - { AFMULDP, yfaddp, Px, 0xde,(01) }, - { AFMULW, yfmvx, Px, 0xde,(01) }, - { AFMULL, yfmvx, Px, 0xda,(01) }, - { AFMULF, yfmvx, Px, 0xd8,(01) }, - { AFMULD, yfadd, Px, 0xdc,(01),0xd8,(01),0xdc,(01) }, - - { AFSUBDP, yfaddp, Px, 0xde,(05) }, - { AFSUBW, yfmvx, Px, 0xde,(04) }, - { AFSUBL, yfmvx, Px, 0xda,(04) }, - { AFSUBF, yfmvx, Px, 0xd8,(04) }, - { AFSUBD, yfadd, Px, 0xdc,(04),0xd8,(04),0xdc,(05) }, - - { AFSUBRDP, yfaddp, Px, 0xde,(04) }, - { AFSUBRW, yfmvx, Px, 0xde,(05) }, - { AFSUBRL, yfmvx, Px, 0xda,(05) }, - { AFSUBRF, yfmvx, Px, 0xd8,(05) }, - { AFSUBRD, yfadd, Px, 0xdc,(05),0xd8,(05),0xdc,(04) }, - - { AFDIVDP, yfaddp, Px, 0xde,(07) }, - { AFDIVW, yfmvx, Px, 0xde,(06) }, - { AFDIVL, yfmvx, Px, 0xda,(06) }, - { AFDIVF, yfmvx, Px, 0xd8,(06) }, - { AFDIVD, yfadd, Px, 0xdc,(06),0xd8,(06),0xdc,(07) }, - - { AFDIVRDP, yfaddp, Px, 0xde,(06) }, - { AFDIVRW, yfmvx, Px, 0xde,(07) }, - { AFDIVRL, yfmvx, Px, 0xda,(07) }, - { AFDIVRF, yfmvx, Px, 0xd8,(07) }, - { AFDIVRD, yfadd, Px, 0xdc,(07),0xd8,(07),0xdc,(06) }, - - { AFXCHD, yfxch, Px, 0xd9,(01),0xd9,(01) }, - { AFFREE }, - { AFLDCW, ystcw, Px, 0xd9,(05),0xd9,(05) }, - { AFLDENV, ystcw, Px, 0xd9,(04),0xd9,(04) }, - { AFRSTOR, ysvrs, Px, 0xdd,(04),0xdd,(04) }, - { AFSAVE, ysvrs, Px, 0xdd,(06),0xdd,(06) }, - { AFSTCW, ystcw, Px, 0xd9,(07),0xd9,(07) }, - { AFSTENV, ystcw, Px, 0xd9,(06),0xd9,(06) }, - { AFSTSW, ystsw, Px, 0xdd,(07),0xdf,0xe0 }, - { AF2XM1, ynone, Px, 0xd9, 0xf0 }, - { AFABS, ynone, Px, 0xd9, 0xe1 }, - { AFCHS, ynone, Px, 0xd9, 0xe0 }, - { AFCLEX, ynone, Px, 0xdb, 0xe2 }, - { AFCOS, ynone, Px, 0xd9, 0xff }, - { AFDECSTP, ynone, Px, 0xd9, 0xf6 }, - { AFINCSTP, ynone, Px, 0xd9, 0xf7 }, - { AFINIT, ynone, Px, 0xdb, 0xe3 }, - { AFLD1, ynone, Px, 0xd9, 0xe8 }, - { AFLDL2E, ynone, Px, 0xd9, 0xea }, - { AFLDL2T, ynone, Px, 0xd9, 0xe9 }, - { AFLDLG2, ynone, Px, 0xd9, 0xec }, - { AFLDLN2, ynone, Px, 0xd9, 0xed }, - { AFLDPI, ynone, Px, 0xd9, 0xeb }, - { AFLDZ, ynone, Px, 0xd9, 0xee }, - { AFNOP, ynone, Px, 0xd9, 0xd0 }, - { AFPATAN, ynone, Px, 0xd9, 0xf3 }, - { AFPREM, ynone, Px, 0xd9, 0xf8 }, - { AFPREM1, ynone, Px, 0xd9, 0xf5 }, - { AFPTAN, ynone, Px, 0xd9, 0xf2 }, - { AFRNDINT, ynone, Px, 0xd9, 0xfc }, - { AFSCALE, ynone, Px, 0xd9, 0xfd }, - { AFSIN, ynone, Px, 0xd9, 0xfe }, - { AFSINCOS, ynone, Px, 0xd9, 0xfb }, - { AFSQRT, ynone, Px, 0xd9, 0xfa }, - { AFTST, ynone, Px, 0xd9, 0xe4 }, - { AFXAM, ynone, Px, 0xd9, 0xe5 }, - { AFXTRACT, ynone, Px, 0xd9, 0xf4 }, - { AFYL2X, ynone, Px, 0xd9, 0xf1 }, - { AFYL2XP1, ynone, Px, 0xd9, 0xf9 }, - - { ACMPXCHGB, yrb_mb, Pb, 0x0f,0xb0 }, - { ACMPXCHGL, yrl_ml, Px, 0x0f,0xb1 }, - { ACMPXCHGW, yrl_ml, Pe, 0x0f,0xb1 }, - { ACMPXCHGQ, yrl_ml, Pw, 0x0f,0xb1 }, - { ACMPXCHG8B, yscond, Pm, 0xc7,(01) }, - { AINVD, ynone, Pm, 0x08 }, - { AINVLPG, ymbs, Pm, 0x01,(07) }, - { ALFENCE, ynone, Pm, 0xae,0xe8 }, - { AMFENCE, ynone, Pm, 0xae,0xf0 }, - { AMOVNTIL, yrl_ml, Pm, 0xc3 }, - { AMOVNTIQ, yrl_ml, Pw, 0x0f,0xc3 }, - { ARDMSR, ynone, Pm, 0x32 }, - { ARDPMC, ynone, Pm, 0x33 }, - { ARDTSC, ynone, Pm, 0x31 }, - { ARSM, ynone, Pm, 0xaa }, - { ASFENCE, ynone, Pm, 0xae,0xf8 }, - { ASYSRET, ynone, Pm, 0x07 }, - { AWBINVD, ynone, Pm, 0x09 }, - { AWRMSR, ynone, Pm, 0x30 }, - - { AXADDB, yrb_mb, Pb, 0x0f,0xc0 }, - { AXADDL, yrl_ml, Px, 0x0f,0xc1 }, - { AXADDQ, yrl_ml, Pw, 0x0f,0xc1 }, - { AXADDW, yrl_ml, Pe, 0x0f,0xc1 }, - - { ACRC32B, ycrc32l,Px, 0xf2,0x0f,0x38,0xf0,0 }, - { ACRC32Q, ycrc32l,Pw, 0xf2,0x0f,0x38,0xf1,0 }, - - { APREFETCHT0, yprefetch, Pm, 0x18,(01) }, - { APREFETCHT1, yprefetch, Pm, 0x18,(02) }, - { APREFETCHT2, yprefetch, Pm, 0x18,(03) }, - { APREFETCHNTA, yprefetch, Pm, 0x18,(00) }, - - { AMOVQL, yrl_ml, Px, 0x89 }, - - { AUNDEF, ynone, Px, 0x0f, 0x0b }, - - { AAESENC, yaes, Pq, 0x38,0xdc,(0) }, - { AAESENCLAST, yaes, Pq, 0x38,0xdd,(0) }, - { AAESDEC, yaes, Pq, 0x38,0xde,(0) }, - { AAESDECLAST, yaes, Pq, 0x38,0xdf,(0) }, - { AAESIMC, yaes, Pq, 0x38,0xdb,(0) }, - { AAESKEYGENASSIST, yaes2, Pq, 0x3a,0xdf,(0) }, - - { APSHUFD, yaes2, Pq, 0x70,(0) }, - { APCLMULQDQ, yxshuf, Pq, 0x3a,0x44,0 }, - - { AUSEFIELD, ynop, Px, 0,0 }, - { AFUNCDATA, yfuncdata, Px, 0,0 }, - { APCDATA, ypcdata, Px, 0,0 }, - - { AEND }, - 0 -}; - -Optab* opindex[ALAST+1]; - -/* -AMOVD 0f 6e/r mmx,reg/mem32[mem64-rex?] -AMOVD 0f 7e/r reg/mem32[64],mmx STORE -AMOVQ 0f 6f/r mmx1,mmx2/mem64 -AMOVQ 0f 7f/r mmx1/mem64,mmx2 -*/ diff --git a/src/cmd/6l/pass.c b/src/cmd/6l/pass.c deleted file mode 100644 index 1be3c18fe..000000000 --- a/src/cmd/6l/pass.c +++ /dev/null @@ -1,991 +0,0 @@ -// Inferno utils/6l/pass.c -// http://code.google.com/p/inferno-os/source/browse/utils/6l/pass.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. - -// Code and data passes. - -#include "l.h" -#include "../ld/lib.h" -#include "../../pkg/runtime/stack.h" - -static void xfol(Prog*, Prog**); - -Prog* -brchain(Prog *p) -{ - int i; - - for(i=0; i<20; i++) { - if(p == P || p->as != AJMP) - return p; - p = p->pcond; - } - return P; -} - -void -follow(void) -{ - Prog *firstp, *lastp; - - if(debug['v']) - Bprint(&bso, "%5.2f follow\n", cputime()); - Bflush(&bso); - - for(cursym = textp; cursym != nil; cursym = cursym->next) { - firstp = prg(); - lastp = firstp; - xfol(cursym->text, &lastp); - lastp->link = nil; - cursym->text = firstp->link; - } -} - -static int -nofollow(int a) -{ - switch(a) { - case AJMP: - case ARET: - case AIRETL: - case AIRETQ: - case AIRETW: - case ARETFL: - case ARETFQ: - case ARETFW: - case AUNDEF: - 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; - enum as a; - -loop: - if(p == P) - return; - 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) { - /* - * 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 == *last) - break; - a = q->as; - if(a == ANOP) { - i--; - continue; - } - 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) - continue; - for(;;) { - if(p->as == ANOP) { - p = p->link; - continue; - } - q = copyp(p); - p = p->link; - q->mark = 1; - (*last)->link = q; - *last = q; - if(q->as != a || q->pcond == P || q->pcond->mark) - continue; - - q->as = relinv(q->as); - p = q->pcond; - q->pcond = q->link; - q->link = p; - xfol(q->link, last); - p = q->link; - if(p->mark) - return; - goto loop; - } - } /* */ - q = prg(); - q->as = AJMP; - q->line = p->line; - q->to.type = D_BRANCH; - q->to.offset = p->pc; - q->pcond = p; - p = q; - } - - /* emit p */ - p->mark = 1; - (*last)->link = p; - *last = p; - a = p->as; - - /* continue loop with what comes after p */ - if(nofollow(a)) - return; - if(p->pcond != P && a != ACALL) { - /* - * some kind of conditional branch. - * recurse to follow one path. - * continue loop on the other. - */ - if((q = brchain(p->pcond)) != P) - p->pcond = q; - if((q = brchain(p->link)) != P) - p->link = q; - if(p->from.type == D_CONST) { - if(p->from.offset == 1) { - /* - * expect conditional jump to be taken. - * rewrite so that's the fall-through case. - */ - p->as = relinv(a); - q = p->link; - p->link = p->pcond; - p->pcond = q; - } - } else { - q = p->link; - if(q->mark) - if(a != ALOOP) { - p->as = relinv(a); - p->link = p->pcond; - p->pcond = q; - } - } - xfol(p->link, last); - if(p->pcond->mark) - return; - p = p->pcond; - goto loop; - } - p = p->link; - goto loop; -} - -Prog* -byteq(int v) -{ - Prog *p; - - p = prg(); - p->as = ABYTE; - p->from.type = D_CONST; - p->from.offset = v&0xff; - return p; -} - -int -relinv(int a) -{ - - switch(a) { - case AJEQ: return AJNE; - case AJNE: return AJEQ; - case AJLE: return AJGT; - case AJLS: return AJHI; - case AJLT: return AJGE; - case AJMI: return AJPL; - case AJGE: return AJLT; - case AJPL: return AJMI; - case AJGT: return AJLE; - case AJHI: return AJLS; - case AJCS: return AJCC; - case AJCC: return AJCS; - case AJPS: return AJPC; - case AJPC: return AJPS; - case AJOS: return AJOC; - case AJOC: return AJOS; - } - diag("unknown relation: %s in %s", anames[a], TNAME); - errorexit(); - return a; -} - -void -patch(void) -{ - int32 c; - Prog *p, *q; - Sym *s; - int32 vexit; - Sym *gmsym; - - if(debug['v']) - Bprint(&bso, "%5.2f mkfwd\n", cputime()); - Bflush(&bso); - mkfwd(); - if(debug['v']) - Bprint(&bso, "%5.2f patch\n", cputime()); - Bflush(&bso); - - if(flag_shared) { - s = lookup("init_array", 0); - s->type = SINITARR; - s->reachable = 1; - s->hide = 1; - addaddr(s, lookup(INITENTRY, 0)); - } - - gmsym = lookup("runtime.tlsgm", 0); - if(linkmode != LinkExternal) - gmsym->reachable = 0; - s = lookup("exit", 0); - vexit = s->value; - for(cursym = textp; cursym != nil; cursym = cursym->next) - for(p = cursym->text; p != P; p = p->link) { - if(HEADTYPE == Hwindows) { - // Windows - // Convert - // op n(GS), reg - // to - // MOVL 0x28(GS), reg - // op n(reg), reg - // The purpose of this patch is to fix some accesses - // to extern register variables (TLS) on Windows, as - // a different method is used to access them. - if(p->from.type == D_INDIR+D_GS - && p->to.type >= D_AX && p->to.type <= D_DI - && p->from.offset <= 8) { - q = appendp(p); - q->from = p->from; - q->from.type = D_INDIR + p->to.type; - q->to = p->to; - q->as = p->as; - p->as = AMOVQ; - p->from.type = D_INDIR+D_GS; - p->from.offset = 0x28; - } - } - if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd - || HEADTYPE == Hopenbsd || HEADTYPE == Hnetbsd - || HEADTYPE == Hplan9x64 || HEADTYPE == Hdragonfly) { - // 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->from.index == D_GS) - p->from.index = D_FS; - if(p->to.index == D_GS) - p->to.index = D_FS; - } - if(!flag_shared) { - // Convert g() or m() accesses of the form - // op n(reg)(GS*1), reg - // to - // op n(GS*1), reg - if(p->from.index == D_FS || p->from.index == D_GS) { - p->from.type = D_INDIR + p->from.index; - p->from.index = D_NONE; - } - // Convert g() or m() accesses of the form - // op reg, n(reg)(GS*1) - // to - // op reg, n(GS*1) - if(p->to.index == D_FS || p->to.index == D_GS) { - p->to.type = D_INDIR + p->to.index; - p->to.index = D_NONE; - } - // Convert get_tls access of the form - // op runtime.tlsgm(SB), reg - // to - // NOP - if(gmsym != S && p->from.sym == gmsym) { - p->as = ANOP; - p->from.type = D_NONE; - p->to.type = D_NONE; - p->from.sym = nil; - p->to.sym = nil; - continue; - } - } else { - // Convert TLS reads of the form - // op n(GS), reg - // to - // MOVQ $runtime.tlsgm(SB), reg - // op n(reg)(GS*1), reg - if((p->from.type == D_INDIR+D_FS || p->from.type == D_INDIR + D_GS) && p->to.type >= D_AX && p->to.type <= D_DI) { - q = appendp(p); - q->to = p->to; - q->as = p->as; - q->from.type = D_INDIR+p->to.type; - q->from.index = p->from.type - D_INDIR; - q->from.scale = 1; - q->from.offset = p->from.offset; - p->as = AMOVQ; - p->from.type = D_EXTERN; - p->from.sym = gmsym; - p->from.offset = 0; - } - } - if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH) || (p->as == ARET && p->to.sym != nil)) { - s = p->to.sym; - if(s) { - if(debug['c']) - Bprint(&bso, "%s calls %s\n", TNAME, s->name); - if((s->type&SMASK) != 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(q == P) { - diag("branch out of range in %s (%#ux)\n%P [%s]", - TNAME, c, p, p->to.sym ? p->to.sym->name : ""); - p->to.type = D_NONE; - } - p->pcond = q; - } - - 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 = brloop(p->pcond); - if(p->pcond != P) - if(p->to.type == D_BRANCH) - p->to.offset = p->pcond->pc; - } - } -} - -Prog* -brloop(Prog *p) -{ - int c; - Prog *q; - - c = 0; - for(q = p; q != P; q = q->pcond) { - if(q->as != AJMP) - break; - c++; - if(c >= 5000) - return P; - } - return q; -} - -static char* -morename[] = -{ - "runtime.morestack00", - "runtime.morestack10", - "runtime.morestack01", - "runtime.morestack11", - - "runtime.morestack8", - "runtime.morestack16", - "runtime.morestack24", - "runtime.morestack32", - "runtime.morestack40", - "runtime.morestack48", -}; -Prog* pmorestack[nelem(morename)]; -Sym* symmorestack[nelem(morename)]; -Sym* gmsym; - -static Prog* load_g_cx(Prog*); -static Prog* stacksplit(Prog*, int32, Prog**); - -void -dostkoff(void) -{ - Prog *p, *q, *q1; - int32 autoffset, deltasp; - int a, pcsize; - uint32 i; - - gmsym = lookup("runtime.tlsgm", 0); - for(i=0; itype != STEXT) - diag("morestack trampoline not defined - %s", morename[i]); - pmorestack[i] = symmorestack[i]->text; - } - - for(cursym = textp; cursym != nil; cursym = cursym->next) { - if(cursym->text == nil || cursym->text->link == nil) - continue; - - p = cursym->text; - parsetextconst(p->to.offset); - autoffset = textstksiz; - if(autoffset < 0) - autoffset = 0; - - if(autoffset < StackSmall && !(p->from.scale & NOSPLIT)) { - for(q = p; q != P; q = q->link) - if(q->as == ACALL) - goto noleaf; - p->from.scale |= NOSPLIT; - noleaf:; - } - - if((p->from.scale & NOSPLIT) && autoffset >= StackSmall) - diag("nosplit func likely to overflow stack"); - - q = P; - if(!(p->from.scale & NOSPLIT) || (p->from.scale & WRAPPER)) { - p = appendp(p); - p = load_g_cx(p); // load g into CX - } - if(!(cursym->text->from.scale & NOSPLIT)) - p = stacksplit(p, autoffset, &q); // emit split check - - if(autoffset) { - p = appendp(p); - p->as = AADJSP; - p->from.type = D_CONST; - p->from.offset = autoffset; - p->spadj = autoffset; - } else { - // zero-byte stack adjustment. - // Insert a fake non-zero adjustment so that stkcheck can - // recognize the end of the stack-splitting prolog. - p = appendp(p); - p->as = ANOP; - p->spadj = -PtrSize; - p = appendp(p); - p->as = ANOP; - p->spadj = PtrSize; - } - if(q != P) - q->pcond = p; - deltasp = autoffset; - - if(cursym->text->from.scale & WRAPPER) { - // g->panicwrap += autoffset + PtrSize; - p = appendp(p); - p->as = AADDL; - p->from.type = D_CONST; - p->from.offset = autoffset + PtrSize; - p->to.type = D_INDIR+D_CX; - p->to.offset = 2*PtrSize; - } - - 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_CX; - p->from.offset = 0; - p->to.type = D_BX; - - p = appendp(p); - p->as = ASUBQ; - 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 = 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; - } - - if(debug['Z'] && autoffset && !(cursym->text->from.scale&NOSPLIT)) { - // 6l -Z means zero the stack frame on entry. - // This slows down function calls but can help avoid - // false positives in garbage collection. - p = appendp(p); - p->as = AMOVQ; - p->from.type = D_SP; - p->to.type = D_DI; - - p = appendp(p); - p->as = AMOVQ; - p->from.type = D_CONST; - p->from.offset = autoffset/8; - p->to.type = D_CX; - - p = appendp(p); - p->as = AMOVQ; - p->from.type = D_CONST; - p->from.offset = 0; - p->to.type = D_AX; - - p = appendp(p); - p->as = AREP; - - p = appendp(p); - p->as = ASTOSQ; - } - - 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(cursym->text->from.scale & WRAPPER) { - p = load_g_cx(p); - p = appendp(p); - // g->panicwrap -= autoffset + PtrSize; - p->as = ASUBL; - p->from.type = D_CONST; - p->from.offset = autoffset + PtrSize; - p->to.type = D_INDIR+D_CX; - p->to.offset = 2*PtrSize; - p = appendp(p); - p->as = ARET; - } - - if(autoffset) { - p->as = AADJSP; - p->from.type = D_CONST; - p->from.offset = -autoffset; - p->spadj = -autoffset; - p = appendp(p); - p->as = ARET; - // If there are instructions following - // this ARET, they come from a branch - // with the same stackframe, so undo - // the cleanup. - p->spadj = +autoffset; - } - if(p->to.sym) // retjmp - p->as = AJMP; - } - } -} - -// Append code to p to load g into cx. -// Overwrites p with the first instruction (no first appendp). -// Overwriting p is unusual but it lets use this in both the -// prologue (caller must call appendp first) and in the epilogue. -// Returns last new instruction. -static Prog* -load_g_cx(Prog *p) -{ - if(flag_shared) { - // Load TLS offset with MOVQ $runtime.tlsgm(SB), CX - p->as = AMOVQ; - p->from.type = D_EXTERN; - p->from.sym = gmsym; - p->to.type = D_CX; - p = appendp(p); - } - p->as = AMOVQ; - if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd - || HEADTYPE == Hopenbsd || HEADTYPE == Hnetbsd - || HEADTYPE == Hplan9x64 || HEADTYPE == Hdragonfly) - // ELF uses FS - p->from.type = D_INDIR+D_FS; - else - p->from.type = D_INDIR+D_GS; - if(flag_shared) { - // Add TLS offset stored in CX - p->from.index = p->from.type - D_INDIR; - p->from.type = D_INDIR + D_CX; - } - p->from.offset = tlsoffset+0; - p->to.type = D_CX; - if(HEADTYPE == Hwindows) { - // movq %gs:0x28, %rcx - // movq (%rcx), %rcx - p->as = AMOVQ; - p->from.type = D_INDIR+D_GS; - p->from.offset = 0x28; - p->to.type = D_CX; - - p = appendp(p); - p->as = AMOVQ; - p->from.type = D_INDIR+D_CX; - p->from.offset = 0; - p->to.type = D_CX; - } - return p; -} - -// Append code to p to check for stack split. -// Appends to (does not overwrite) p. -// Assumes g is in CX. -// Returns last new instruction. -// On return, *jmpok is the instruction that should jump -// to the stack frame allocation if no split is needed. -static Prog* -stacksplit(Prog *p, int32 framesize, Prog **jmpok) -{ - Prog *q, *q1; - uint32 moreconst1, moreconst2, i; - - 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_CX; - 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; - - p = appendp(p); - p->as = ANOP; - q1->pcond = p; - } - - q = P; - q1 = P; - if(framesize <= StackSmall) { - // small stack: SP <= stackguard - // CMPQ SP, stackguard - p = appendp(p); - p->as = ACMPQ; - p->from.type = D_SP; - p->to.type = D_INDIR+D_CX; - } else if(framesize <= StackBig) { - // large stack: SP-framesize <= stackguard-StackSmall - // LEAQ -xxx(SP), AX - // CMPQ AX, stackguard - p = appendp(p); - p->as = ALEAQ; - p->from.type = D_INDIR+D_SP; - p->from.offset = -(framesize-StackSmall); - p->to.type = D_AX; - - p = appendp(p); - p->as = ACMPQ; - p->from.type = D_AX; - p->to.type = D_INDIR+D_CX; - } else { - // Such a large stack we need to protect against wraparound. - // If SP is close to zero: - // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall) - // The +StackGuard on both sides is required to keep the left side positive: - // SP is allowed to be slightly below stackguard. See stack.h. - // - // Preemption sets stackguard to StackPreempt, a very large value. - // That breaks the math above, so we have to check for that explicitly. - // MOVQ stackguard, CX - // CMPQ CX, $StackPreempt - // JEQ label-of-call-to-morestack - // LEAQ StackGuard(SP), AX - // SUBQ CX, AX - // CMPQ AX, $(framesize+(StackGuard-StackSmall)) - - p = appendp(p); - p->as = AMOVQ; - p->from.type = D_INDIR+D_CX; - p->from.offset = 0; - p->to.type = D_SI; - - p = appendp(p); - p->as = ACMPQ; - p->from.type = D_SI; - p->to.type = D_CONST; - p->to.offset = StackPreempt; - - p = appendp(p); - p->as = AJEQ; - p->to.type = D_BRANCH; - q1 = p; - - p = appendp(p); - p->as = ALEAQ; - p->from.type = D_INDIR+D_SP; - p->from.offset = StackGuard; - p->to.type = D_AX; - - p = appendp(p); - p->as = ASUBQ; - p->from.type = D_SI; - p->to.type = D_AX; - - p = appendp(p); - p->as = ACMPQ; - p->from.type = D_AX; - p->to.type = D_CONST; - p->to.offset = framesize+(StackGuard-StackSmall); - } - - // common - p = appendp(p); - p->as = AJHI; - p->to.type = D_BRANCH; - q = p; - - // If we ask for more stack, we'll get a minimum of StackMin bytes. - // We need a stack frame large enough to hold the top-of-stack data, - // the function arguments+results, our caller's PC, our frame, - // a word for the return PC of the next call, and then the StackLimit bytes - // that must be available on entry to any function called from a function - // that did a stack check. If StackMin is enough, don't ask for a specific - // amount: then we can use the custom functions and save a few - // instructions. - moreconst1 = 0; - if(StackTop + textarg + PtrSize + framesize + PtrSize + StackLimit >= StackMin) - moreconst1 = framesize; - moreconst2 = textarg; - if(moreconst2 == 1) // special marker - moreconst2 = 0; - if((moreconst2&7) != 0) - diag("misaligned argument size in stack split"); - // 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 = moreconst1; - p->to.type = D_AX; - - 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]; - } 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 = 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 = (uint64)moreconst2 << 32; - p->from.offset |= moreconst1; - p->to.type = D_AX; - - p = appendp(p); - p->as = ACALL; - p->to.type = D_BRANCH; - p->pcond = pmorestack[3]; - p->to.sym = symmorestack[3]; - } - - p = appendp(p); - p->as = AJMP; - p->to.type = D_BRANCH; - p->pcond = cursym->text->link; - - if(q != P) - q->pcond = p->link; - if(q1 != P) - q1->pcond = q->link; - - *jmpok = q; - return p; -} - -vlong -atolwhex(char *s) -{ - vlong n; - int f; - - n = 0; - f = 0; - while(*s == ' ' || *s == '\t') - s++; - if(*s == '-' || *s == '+') { - if(*s++ == '-') - f = 1; - while(*s == ' ' || *s == '\t') - s++; - } - if(s[0]=='0' && s[1]){ - if(s[1]=='x' || s[1]=='X'){ - s += 2; - for(;;){ - if(*s >= '0' && *s <= '9') - n = n*16 + *s++ - '0'; - else if(*s >= 'a' && *s <= 'f') - n = n*16 + *s++ - 'a' + 10; - else if(*s >= 'A' && *s <= 'F') - n = n*16 + *s++ - 'A' + 10; - else - break; - } - } else - while(*s >= '0' && *s <= '7') - n = n*8 + *s++ - '0'; - } else - while(*s >= '0' && *s <= '9') - n = n*10 + *s++ - '0'; - if(f) - n = -n; - return n; -} diff --git a/src/cmd/6l/prof.c b/src/cmd/6l/prof.c deleted file mode 100644 index 862ce080c..000000000 --- a/src/cmd/6l/prof.c +++ /dev/null @@ -1,171 +0,0 @@ -// 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) -{ -#ifdef NOTDEF - 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 deleted file mode 100644 index 74f11d635..000000000 --- a/src/cmd/6l/span.c +++ /dev/null @@ -1,1846 +0,0 @@ -// 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. - -// Instruction layout. - -#include "l.h" -#include "../ld/lib.h" -#include "../ld/elf.h" - -static int rexflag; -static int asmode; -static vlong vaddr(Adr*, Reloc*); - -// single-instruction no-ops of various lengths. -// constructed by hand and disassembled with gdb to verify. -// see http://www.agner.org/optimize/optimizing_assembly.pdf for discussion. -static uchar nop[][16] = { - {0x90}, - {0x66, 0x90}, - {0x0F, 0x1F, 0x00}, - {0x0F, 0x1F, 0x40, 0x00}, - {0x0F, 0x1F, 0x44, 0x00, 0x00}, - {0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00}, - {0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00}, - {0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x66, 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}, -}; - -static void -fillnop(uchar *p, int n) -{ - int m; - - while(n > 0) { - m = n; - if(m > nelem(nop)) - m = nelem(nop); - memmove(p, nop[m-1], m); - p += m; - n -= m; - } -} - -void -span1(Sym *s) -{ - Prog *p, *q; - 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 - q->back |= 4; // loop head - } - - 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; - } - } - - 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) { - if((p->back & 4) && (c&(LoopAlign-1)) != 0) { - // pad with NOPs - v = -c&(LoopAlign-1); - if(v <= MaxLoopPad) { - symgrow(s, c+v); - fillnop(s->p+c, v); - c += v; - } - } - - 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; - } - if(q->as == AJCXZL) - s->p[q->pc+2] = v; - else - 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(); - } - } 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; inp; i++) { - print(" %.2ux", s->p[i]); - if(i%16 == 15) - print("\n %.6ux", i+1); - } - if(i%16) - print("\n"); - - for(i=0; inr; i++) { - Reloc *r; - - r = &s->r[i]; - print(" rel %#.4ux/%d %s%+lld\n", r->off, r->siz, r->sym->name, r->add); - } - } -} - -void -span(void) -{ - Prog *p, *q; - int32 v; - int n; - - if(debug['v']) - Bprint(&bso, "%5.2f span\n", cputime()); - - // 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; - } - } - span1(cursym); - } -} - -void -xdefine(char *p, int t, vlong v) -{ - Sym *s; - - s = lookup(p, 0); - s->type = t; - s->value = v; - s->reachable = 1; - s->special = 1; -} - -void -instinit(void) -{ - int c, i; - - 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= 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; - } -} - -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; - } - switch(a->index) { - case D_CS: - return 0x2e; - case D_DS: - return 0x3e; - case D_ES: - return 0x26; - case D_FS: - return 0x64; - case D_GS: - return 0x65; - } - return 0; -} - -int -oclass(Adr *a) -{ - vlong v; - int32 l; - - if(a->type >= D_INDIR || a->index != D_NONE) { - if(a->index != D_NONE && a->scale == 0) { - if(a->type == D_ADDR) { - switch(a->index) { - case D_EXTERN: - case D_STATIC: - if(flag_shared) - return Yiauto; - else - return Yi32; /* TO DO: Yi64 */ - case D_AUTO: - case D_PARAM: - return Yiauto; - } - return Yxxx; - } - return Ycol; - } - return Ym; - } - switch(a->type) - { - case D_AL: - return Yal; - - case D_AX: - return Yax; - -/* - case D_SPB: -*/ - case D_BPB: - case D_SIB: - case D_DIB: - case D_R8B: - case D_R9B: - case D_R10B: - case D_R11B: - case D_R12B: - case D_R13B: - case D_R14B: - case D_R15B: - if(asmode != 64) - return Yxxx; - case D_DL: - case D_BL: - case D_AH: - case D_CH: - case D_DH: - case D_BH: - return Yrb; - - case D_CL: - return Ycl; - - case D_CX: - return Ycx; - - case D_DX: - case D_BX: - return Yrx; - - case D_R8: /* not really Yrl */ - case D_R9: - case D_R10: - case D_R11: - case D_R12: - case D_R13: - case D_R14: - case D_R15: - if(asmode != 64) - return Yxxx; - case D_SP: - case D_BP: - case D_SI: - case D_DI: - return Yrl; - - case D_F0+0: - return Yf0; - - case D_F0+1: - case D_F0+2: - case D_F0+3: - case D_F0+4: - case D_F0+5: - case D_F0+6: - case D_F0+7: - return Yrf; - - case D_M0+0: - case D_M0+1: - case D_M0+2: - case D_M0+3: - case D_M0+4: - case D_M0+5: - case D_M0+6: - case D_M0+7: - return Ymr; - - case D_X0+0: - case D_X0+1: - case D_X0+2: - case D_X0+3: - case D_X0+4: - case D_X0+5: - case D_X0+6: - case D_X0+7: - case D_X0+8: - case D_X0+9: - case D_X0+10: - case D_X0+11: - case D_X0+12: - case D_X0+13: - case D_X0+14: - case D_X0+15: - return Yxr; - - case D_NONE: - return Ynone; - - case D_CS: return Ycs; - case D_SS: return Yss; - case D_DS: return Yds; - case D_ES: return Yes; - case D_FS: return Yfs; - case D_GS: return Ygs; - - case D_GDTR: return Ygdtr; - case D_IDTR: return Yidtr; - case D_LDTR: return Yldtr; - case D_MSW: return Ymsw; - case D_TASK: return Ytask; - - case D_CR+0: return Ycr0; - case D_CR+1: return Ycr1; - case D_CR+2: return Ycr2; - case D_CR+3: return Ycr3; - case D_CR+4: return Ycr4; - case D_CR+5: return Ycr5; - case D_CR+6: return Ycr6; - case D_CR+7: return Ycr7; - case D_CR+8: return Ycr8; - - case D_DR+0: return Ydr0; - case D_DR+1: return Ydr1; - case D_DR+2: return Ydr2; - case D_DR+3: return Ydr3; - case D_DR+4: return Ydr4; - case D_DR+5: return Ydr5; - case D_DR+6: return Ydr6; - case D_DR+7: return Ydr7; - - case D_TR+0: return Ytr0; - case D_TR+1: return Ytr1; - case D_TR+2: return Ytr2; - case D_TR+3: return Ytr3; - case D_TR+4: return Ytr4; - case D_TR+5: return Ytr5; - case D_TR+6: return Ytr6; - case D_TR+7: return Ytr7; - - case D_EXTERN: - case D_STATIC: - case D_AUTO: - case D_PARAM: - return Ym; - - case D_CONST: - case D_ADDR: - if(a->sym == S) { - v = a->offset; - if(v == 0) - return Yi0; - if(v == 1) - return Yi1; - if(v >= -128 && v <= 127) - return Yi8; - l = v; - if((vlong)l == v) - return Ys32; /* can sign extend */ - if((v>>32) == 0) - return Yi32; /* unsigned */ - return Yi64; - } - return Yi32; /* TO DO: D_ADDR as Yi64 */ - - case D_BRANCH: - return Ybr; - } - return Yxxx; -} - -void -asmidx(int scale, int index, int base) -{ - int i; - - switch(index) { - default: - goto bad; - - case D_NONE: - i = 4 << 3; - goto bas; - - case D_R8: - case D_R9: - case D_R10: - case D_R11: - case D_R12: - case D_R13: - case D_R14: - case D_R15: - if(asmode != 64) - goto bad; - case D_AX: - case D_CX: - case D_DX: - case D_BX: - case D_BP: - case D_SI: - case D_DI: - i = reg[index] << 3; - break; - } - switch(scale) { - default: - goto bad; - case 1: - break; - case 2: - i |= (1<<6); - break; - case 4: - i |= (2<<6); - break; - case 8: - i |= (3<<6); - break; - } -bas: - switch(base) { - default: - goto bad; - case D_NONE: /* must be mod=00 */ - i |= 5; - break; - case D_R8: - case D_R9: - case D_R10: - case D_R11: - case D_R12: - case D_R13: - case D_R14: - case D_R15: - if(asmode != 64) - goto bad; - case D_AX: - case D_CX: - case D_DX: - case D_BX: - case D_SP: - case D_BP: - case D_SI: - case D_DI: - i |= reg[base]; - break; - } - *andptr++ = i; - return; -bad: - diag("asmidx: bad address %d/%d/%d", scale, index, base); - *andptr++ = 0; - return; -} - -static void -put4(int32 v) -{ - andptr[0] = v; - andptr[1] = v>>8; - andptr[2] = v>>16; - andptr[3] = v>>24; - 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); -} - -static void -put8(vlong v) -{ - andptr[0] = v; - andptr[1] = v>>8; - andptr[2] = v>>16; - andptr[3] = v>>24; - andptr[4] = v>>32; - andptr[5] = v>>40; - andptr[6] = v>>48; - andptr[7] = v>>56; - 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) -{ - if(!s->reachable) - diag("unreachable symbol in symaddr - %s", s->name); - return s->value; -} - -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; - if(t == D_ADDR) - t = a->index; - switch(t) { - case D_STATIC: - case D_EXTERN: - s = a->sym; - if(!s->reachable) - diag("unreachable symbol in vaddr - %s", s->name); - if(r == nil) { - diag("need reloc for %D", a); - errorexit(); - } - r->siz = 4; // TODO: 8 for external symbols - r->off = -1; // caller must fill in - r->sym = s; - r->add = v; - v = 0; - if(flag_shared) { - if(s->type == STLSBSS) { - r->xadd = r->add - r->siz; - r->type = D_TLS; - r->xsym = s; - } else - r->type = D_PCREL; - } else - r->type = D_ADDR; - } - return v; -} - -static void -asmandsz(Adr *a, int r, int rex, int m64) -{ - int32 v; - int t, scale; - Reloc rel; - - USED(m64); - rex &= (0x40 | Rxr); - v = a->offset; - t = a->type; - rel.siz = 0; - if(a->index != D_NONE && a->index != D_FS && a->index != D_GS) { - if(t < D_INDIR) { - switch(t) { - default: - goto bad; - case D_STATIC: - case D_EXTERN: - if(flag_shared) - goto bad; - t = D_NONE; - v = vaddr(a, &rel); - break; - case D_AUTO: - case D_PARAM: - t = D_SP; - break; - } - } 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; - } - 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; - } - 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) - goto bad; - *andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3); - rexflag |= (regrex[t] & (0x40 | Rxb)) | rex; - return; - } - - 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 || (D_CS <= t && t <= D_GS)) { - if(flag_shared && t == D_NONE && (a->type == D_STATIC || a->type == D_EXTERN) || 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(v >= -128 && v < 128) { - *andptr++ = (1 << 6) | (reg[t] << 0) | (r << 3); - asmidx(scale, D_NONE, t); - *andptr++ = v; - return; - } - *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; - } - 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; - } - 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; - } else if(iself && linkmode == LinkExternal && a->type == D_INDIR+D_FS - && HEADTYPE != Hopenbsd) { - Reloc *r; - Sym *s; - - r = addrel(cursym); - r->off = curp->pc + andptr - and; - r->add = a->offset-tlsoffset; - r->xadd = r->add; - r->siz = 4; - r->type = D_TLS; - s = lookup("runtime.tlsgm", 0); - r->sym = s; - r->xsym = s; - v = 0; - } - - put4(v); - return; - -bad: - diag("asmand: bad address %D", a); - return; -} - -void -asmand(Adr *a, Adr *ra) -{ - asmandsz(a, reg[ra->type], regrex[ra->type], 0); -} - -void -asmando(Adr *a, int o) -{ - asmandsz(a, o, 0, 0); -} - -static void -bytereg(Adr *a, char *t) -{ - if(a->index == D_NONE && (a->type >= D_AX && a->type <= D_R15)) { - a->type = D_AL + (a->type-D_AX); - *t = 0; - } -} - -#define E 0xff -Movtab ymovtab[] = -{ -/* push */ - {APUSHL, Ycs, Ynone, 0, 0x0e,E,0,0}, - {APUSHL, Yss, Ynone, 0, 0x16,E,0,0}, - {APUSHL, Yds, Ynone, 0, 0x1e,E,0,0}, - {APUSHL, Yes, Ynone, 0, 0x06,E,0,0}, - {APUSHL, Yfs, Ynone, 0, 0x0f,0xa0,E,0}, - {APUSHL, Ygs, Ynone, 0, 0x0f,0xa8,E,0}, - {APUSHQ, Yfs, Ynone, 0, 0x0f,0xa0,E,0}, - {APUSHQ, Ygs, Ynone, 0, 0x0f,0xa8,E,0}, - - {APUSHW, Ycs, Ynone, 0, Pe,0x0e,E,0}, - {APUSHW, Yss, Ynone, 0, Pe,0x16,E,0}, - {APUSHW, Yds, Ynone, 0, Pe,0x1e,E,0}, - {APUSHW, Yes, Ynone, 0, Pe,0x06,E,0}, - {APUSHW, Yfs, Ynone, 0, Pe,0x0f,0xa0,E}, - {APUSHW, Ygs, Ynone, 0, Pe,0x0f,0xa8,E}, - -/* pop */ - {APOPL, Ynone, Yds, 0, 0x1f,E,0,0}, - {APOPL, Ynone, Yes, 0, 0x07,E,0,0}, - {APOPL, Ynone, Yss, 0, 0x17,E,0,0}, - {APOPL, Ynone, Yfs, 0, 0x0f,0xa1,E,0}, - {APOPL, Ynone, Ygs, 0, 0x0f,0xa9,E,0}, - {APOPQ, Ynone, Yfs, 0, 0x0f,0xa1,E,0}, - {APOPQ, Ynone, Ygs, 0, 0x0f,0xa9,E,0}, - - {APOPW, Ynone, Yds, 0, Pe,0x1f,E,0}, - {APOPW, Ynone, Yes, 0, Pe,0x07,E,0}, - {APOPW, Ynone, Yss, 0, Pe,0x17,E,0}, - {APOPW, Ynone, Yfs, 0, Pe,0x0f,0xa1,E}, - {APOPW, Ynone, Ygs, 0, Pe,0x0f,0xa9,E}, - -/* mov seg */ - {AMOVW, Yes, Yml, 1, 0x8c,0,0,0}, - {AMOVW, Ycs, Yml, 1, 0x8c,1,0,0}, - {AMOVW, Yss, Yml, 1, 0x8c,2,0,0}, - {AMOVW, Yds, Yml, 1, 0x8c,3,0,0}, - {AMOVW, Yfs, Yml, 1, 0x8c,4,0,0}, - {AMOVW, Ygs, Yml, 1, 0x8c,5,0,0}, - - {AMOVW, Yml, Yes, 2, 0x8e,0,0,0}, - {AMOVW, Yml, Ycs, 2, 0x8e,1,0,0}, - {AMOVW, Yml, Yss, 2, 0x8e,2,0,0}, - {AMOVW, Yml, Yds, 2, 0x8e,3,0,0}, - {AMOVW, Yml, Yfs, 2, 0x8e,4,0,0}, - {AMOVW, Yml, Ygs, 2, 0x8e,5,0,0}, - -/* mov cr */ - {AMOVL, Ycr0, Yml, 3, 0x0f,0x20,0,0}, - {AMOVL, Ycr2, Yml, 3, 0x0f,0x20,2,0}, - {AMOVL, Ycr3, Yml, 3, 0x0f,0x20,3,0}, - {AMOVL, Ycr4, Yml, 3, 0x0f,0x20,4,0}, - {AMOVL, Ycr8, Yml, 3, 0x0f,0x20,8,0}, - {AMOVQ, Ycr0, Yml, 3, 0x0f,0x20,0,0}, - {AMOVQ, Ycr2, Yml, 3, 0x0f,0x20,2,0}, - {AMOVQ, Ycr3, Yml, 3, 0x0f,0x20,3,0}, - {AMOVQ, Ycr4, Yml, 3, 0x0f,0x20,4,0}, - {AMOVQ, Ycr8, Yml, 3, 0x0f,0x20,8,0}, - - {AMOVL, Yml, Ycr0, 4, 0x0f,0x22,0,0}, - {AMOVL, Yml, Ycr2, 4, 0x0f,0x22,2,0}, - {AMOVL, Yml, Ycr3, 4, 0x0f,0x22,3,0}, - {AMOVL, Yml, Ycr4, 4, 0x0f,0x22,4,0}, - {AMOVL, Yml, Ycr8, 4, 0x0f,0x22,8,0}, - {AMOVQ, Yml, Ycr0, 4, 0x0f,0x22,0,0}, - {AMOVQ, Yml, Ycr2, 4, 0x0f,0x22,2,0}, - {AMOVQ, Yml, Ycr3, 4, 0x0f,0x22,3,0}, - {AMOVQ, Yml, Ycr4, 4, 0x0f,0x22,4,0}, - {AMOVQ, Yml, Ycr8, 4, 0x0f,0x22,8,0}, - -/* mov dr */ - {AMOVL, Ydr0, Yml, 3, 0x0f,0x21,0,0}, - {AMOVL, Ydr6, Yml, 3, 0x0f,0x21,6,0}, - {AMOVL, Ydr7, Yml, 3, 0x0f,0x21,7,0}, - {AMOVQ, Ydr0, Yml, 3, 0x0f,0x21,0,0}, - {AMOVQ, Ydr6, Yml, 3, 0x0f,0x21,6,0}, - {AMOVQ, Ydr7, Yml, 3, 0x0f,0x21,7,0}, - - {AMOVL, Yml, Ydr0, 4, 0x0f,0x23,0,0}, - {AMOVL, Yml, Ydr6, 4, 0x0f,0x23,6,0}, - {AMOVL, Yml, Ydr7, 4, 0x0f,0x23,7,0}, - {AMOVQ, Yml, Ydr0, 4, 0x0f,0x23,0,0}, - {AMOVQ, Yml, Ydr6, 4, 0x0f,0x23,6,0}, - {AMOVQ, Yml, Ydr7, 4, 0x0f,0x23,7,0}, - -/* mov tr */ - {AMOVL, Ytr6, Yml, 3, 0x0f,0x24,6,0}, - {AMOVL, Ytr7, Yml, 3, 0x0f,0x24,7,0}, - - {AMOVL, Yml, Ytr6, 4, 0x0f,0x26,6,E}, - {AMOVL, Yml, Ytr7, 4, 0x0f,0x26,7,E}, - -/* lgdt, sgdt, lidt, sidt */ - {AMOVL, Ym, Ygdtr, 4, 0x0f,0x01,2,0}, - {AMOVL, Ygdtr, Ym, 3, 0x0f,0x01,0,0}, - {AMOVL, Ym, Yidtr, 4, 0x0f,0x01,3,0}, - {AMOVL, Yidtr, Ym, 3, 0x0f,0x01,1,0}, - {AMOVQ, Ym, Ygdtr, 4, 0x0f,0x01,2,0}, - {AMOVQ, Ygdtr, Ym, 3, 0x0f,0x01,0,0}, - {AMOVQ, Ym, Yidtr, 4, 0x0f,0x01,3,0}, - {AMOVQ, Yidtr, Ym, 3, 0x0f,0x01,1,0}, - -/* lldt, sldt */ - {AMOVW, Yml, Yldtr, 4, 0x0f,0x00,2,0}, - {AMOVW, Yldtr, Yml, 3, 0x0f,0x00,0,0}, - -/* lmsw, smsw */ - {AMOVW, Yml, Ymsw, 4, 0x0f,0x01,6,0}, - {AMOVW, Ymsw, Yml, 3, 0x0f,0x01,4,0}, - -/* ltr, str */ - {AMOVW, Yml, Ytask, 4, 0x0f,0x00,3,0}, - {AMOVW, Ytask, Yml, 3, 0x0f,0x00,1,0}, - -/* load full pointer */ - {AMOVL, Yml, Ycol, 5, 0,0,0,0}, - {AMOVW, Yml, Ycol, 5, Pe,0,0,0}, - -/* double shift */ - {ASHLL, Ycol, Yml, 6, 0xa4,0xa5,0,0}, - {ASHRL, Ycol, Yml, 6, 0xac,0xad,0,0}, - {ASHLQ, Ycol, Yml, 6, Pw,0xa4,0xa5,0}, - {ASHRQ, Ycol, Yml, 6, Pw,0xac,0xad,0}, - {ASHLW, Ycol, Yml, 6, Pe,0xa4,0xa5,0}, - {ASHRW, Ycol, Yml, 6, Pe,0xac,0xad,0}, - 0 -}; - -int -isax(Adr *a) -{ - - switch(a->type) { - case D_AX: - case D_AL: - case D_AH: - case D_INDIR+D_AX: - return 1; - } - if(a->index == D_AX) - return 1; - return 0; -} - -void -subreg(Prog *p, int from, int to) -{ - - if(debug['Q']) - print("\n%P s/%R/%R/\n", p, from, to); - - if(p->from.type == from) - p->from.type = to; - if(p->to.type == from) - p->to.type = to; - - if(p->from.index == from) - p->from.index = to; - if(p->to.index == from) - p->to.index = to; - - from += D_INDIR; - if(p->from.type == from) - p->from.type = to+D_INDIR; - if(p->to.type == from) - p->to.type = to+D_INDIR; - - if(debug['Q']) - print("%P\n", p); -} - -static int -mediaop(Optab *o, int op, int osize, int z) -{ - switch(op){ - case Pm: - case Pe: - case Pf2: - case Pf3: - if(osize != 1){ - if(op != Pm) - *andptr++ = op; - *andptr++ = Pm; - op = o->op[++z]; - break; - } - default: - if(andptr == and || andptr[-1] != Pm) - *andptr++ = Pm; - break; - } - *andptr++ = op; - return z; -} - -void -doasm(Prog *p) -{ - Optab *o; - Prog *q, pp; - uchar *t; - Movtab *mo; - 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); - if(p->tt == 0) - p->tt = oclass(&p->to); - - ft = p->ft * Ymax; - tt = p->tt * Ymax; - - t = o->ytab; - if(t == 0) { - diag("asmins: noproto %P", p); - return; - } - xo = o->op[0] == 0x0f; - for(z=0; *t; z+=t[3]+xo,t+=4) - if(ycover[ft+t[0]]) - if(ycover[tt+t[1]]) - goto found; - goto domov; - -found: - switch(o->prefix) { - case Pq: /* 16 bit escape and opcode escape */ - *andptr++ = Pe; - *andptr++ = Pm; - break; - case Pq3: /* 16 bit escape, Rex.w, and opcode escape */ - *andptr++ = Pe; - *andptr++ = Pw; - *andptr++ = Pm; - break; - - case Pf2: /* xmm opcode escape */ - case Pf3: - *andptr++ = o->prefix; - *andptr++ = Pm; - break; - - case Pm: /* opcode escape */ - *andptr++ = Pm; - break; - - case Pe: /* 16 bit escape */ - *andptr++ = Pe; - break; - - case Pw: /* 64-bit escape */ - if(p->mode != 64) - diag("asmins: illegal 64: %P", p); - rexflag |= Pw; - break; - - case Pb: /* botch */ - bytereg(&p->from, &p->ft); - bytereg(&p->to, &p->tt); - break; - - case P32: /* 32 bit but illegal if 64-bit mode */ - if(p->mode == 64) - diag("asmins: illegal in 64-bit mode: %P", p); - break; - - case Py: /* 64-bit only, no prefix */ - if(p->mode != 64) - diag("asmins: illegal in %d-bit mode: %P", p->mode, p); - break; - } - - if(z >= nelem(o->op)) - sysfatal("asmins bad table %P", p); - op = o->op[z]; - if(op == 0x0f) { - *andptr++ = op; - op = o->op[++z]; - } - switch(t[2]) { - default: - diag("asmins: unknown z %d %P", t[2], p); - return; - - case Zpseudo: - break; - - case Zlit: - for(; op = o->op[z]; z++) - *andptr++ = op; - break; - - case Zlitm_r: - for(; op = o->op[z]; z++) - *andptr++ = op; - asmand(&p->from, &p->to); - break; - - case Zmb_r: - bytereg(&p->from, &p->ft); - /* fall through */ - case Zm_r: - *andptr++ = op; - asmand(&p->from, &p->to); - break; - case Zm2_r: - *andptr++ = op; - *andptr++ = o->op[z+1]; - asmand(&p->from, &p->to); - break; - - case Zm_r_xm: - mediaop(o, op, t[3], z); - asmand(&p->from, &p->to); - break; - - case Zm_r_xm_nr: - rexflag = 0; - mediaop(o, op, t[3], z); - asmand(&p->from, &p->to); - break; - - case Zm_r_i_xm: - mediaop(o, op, t[3], z); - asmand(&p->from, &p->to); - *andptr++ = p->to.offset; - break; - - case Zm_r_3d: - *andptr++ = 0x0f; - *andptr++ = 0x0f; - asmand(&p->from, &p->to); - *andptr++ = op; - break; - - case Zibm_r: - while ((op = o->op[z++]) != 0) - *andptr++ = op; - asmand(&p->from, &p->to); - *andptr++ = p->to.offset; - break; - - case Zaut_r: - *andptr++ = 0x8d; /* leal */ - if(p->from.type != D_ADDR) - diag("asmins: Zaut sb type ADDR"); - p->from.type = p->from.index; - p->from.index = D_NONE; - asmand(&p->from, &p->to); - p->from.index = p->from.type; - p->from.type = D_ADDR; - break; - - case Zm_o: - *andptr++ = op; - asmando(&p->from, o->op[z+1]); - break; - - case Zr_m: - *andptr++ = op; - asmand(&p->to, &p->from); - break; - - case Zr_m_xm: - mediaop(o, op, t[3], z); - asmand(&p->to, &p->from); - break; - - case Zr_m_xm_nr: - rexflag = 0; - mediaop(o, op, t[3], z); - asmand(&p->to, &p->from); - break; - - case Zr_m_i_xm: - mediaop(o, op, t[3], z); - asmand(&p->to, &p->from); - *andptr++ = p->from.offset; - break; - - case Zo_m: - *andptr++ = op; - asmando(&p->to, o->op[z+1]); - break; - - case Zo_m64: - *andptr++ = op; - asmandsz(&p->to, o->op[z+1], 0, 1); - break; - - case Zm_ibo: - *andptr++ = op; - asmando(&p->from, o->op[z+1]); - *andptr++ = vaddr(&p->to, nil); - break; - - case Zibo_m: - *andptr++ = op; - asmando(&p->to, o->op[z+1]); - *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++ = vaddr(&p->from, nil); - break; - - case Z_ib: - case Zib_: - if(t[2] == Zib_) - a = &p->from; - else - a = &p->to; - *andptr++ = op; - *andptr++ = vaddr(a, nil); - break; - - case Zib_rp: - rexflag |= regrex[p->to.type] & (Rxb|0x40); - *andptr++ = op + reg[p->to.type]; - *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 - 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 && 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; - //print("sign: %llux %P\n", v, p); - *andptr ++ = 0xc7; - asmando(&p->to, 0); - put4(v); - }else{ /* need all 8 */ - //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; - - case Zib_rr: - *andptr++ = op; - asmand(&p->to, &p->to); - *andptr++ = vaddr(&p->from, nil); - break; - - case Z_il: - case Zil_: - if(t[2] == Zil_) - a = &p->from; - else - a = &p->to; - *andptr++ = op; - if(o->prefix == Pe) { - v = vaddr(a, nil); - *andptr++ = v; - *andptr++ = v>>8; - } - else - relput4(p, a); - break; - - case Zm_ilo: - case Zilo_m: - *andptr++ = op; - 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 - 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 - relput4(p, &p->from); - break; - - case Z_rp: - rexflag |= regrex[p->to.type] & (Rxb|0x40); - *andptr++ = op + reg[p->to.type]; - break; - - case Zrp_: - rexflag |= regrex[p->from.type] & (Rxb|0x40); - *andptr++ = op + reg[p->from.type]; - break; - - case Zclr: - *andptr++ = op; - asmand(&p->to, &p->to); - break; - - case Zcall: - q = p->pcond; - 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 Zbr: - case Zjmp: - case Zloop: - // TODO: jump across functions needs reloc - q = p->pcond; - if(q == nil) { - diag("jmp/branch/loop without target"); - errorexit(); - } - if(q->as == ATEXT) { - 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) { - if(p->as == AJCXZL) - *andptr++ = 0x67; - *andptr++ = op; - *andptr++ = v; - } else if(t[2] == Zloop) { - diag("loop too far: %P", p); - } 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 - if(p->as == AJCXZL) - *andptr++ = 0x67; - *andptr++ = op; - *andptr++ = 0; - } else if(t[2] == Zloop) { - diag("loop too far: %P", p); - } 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 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; - if(op > 2) { - *andptr++ = v>>16; - *andptr++ = v>>24; - if(op > 4) { - *andptr++ = v>>32; - *andptr++ = v>>40; - *andptr++ = v>>48; - *andptr++ = v>>56; - } - } - } - break; - } - return; - -domov: - for(mo=ymovtab; mo->as; mo++) - if(p->as == mo->as) - if(ycover[ft+mo->ft]) - if(ycover[tt+mo->tt]){ - t = mo->op; - goto mfound; - } -bad: - if(p->mode != 64){ - /* - * here, the assembly has failed. - * if its a byte instruction that has - * unaddressable registers, try to - * exchange registers and reissue the - * instruction with the operands renamed. - */ - pp = *p; - z = p->from.type; - if(z >= D_BP && z <= D_DI) { - if(isax(&p->to) || p->to.type == D_NONE) { - // We certainly don't want to exchange - // with AX if the op is MUL or DIV. - *andptr++ = 0x87; /* xchg lhs,bx */ - asmando(&p->from, reg[D_BX]); - subreg(&pp, z, D_BX); - doasm(&pp); - *andptr++ = 0x87; /* xchg lhs,bx */ - asmando(&p->from, reg[D_BX]); - } else { - *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */ - subreg(&pp, z, D_AX); - doasm(&pp); - *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */ - } - return; - } - z = p->to.type; - if(z >= D_BP && z <= D_DI) { - if(isax(&p->from)) { - *andptr++ = 0x87; /* xchg rhs,bx */ - asmando(&p->to, reg[D_BX]); - subreg(&pp, z, D_BX); - doasm(&pp); - *andptr++ = 0x87; /* xchg rhs,bx */ - asmando(&p->to, reg[D_BX]); - } else { - *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */ - subreg(&pp, z, D_AX); - doasm(&pp); - *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */ - } - return; - } - } - diag("doasm: notfound from=%ux to=%ux %P", p->from.type, p->to.type, p); - return; - -mfound: - switch(mo->code) { - default: - diag("asmins: unknown mov %d %P", mo->code, p); - break; - - case 0: /* lit */ - for(z=0; t[z]!=E; z++) - *andptr++ = t[z]; - break; - - case 1: /* r,m */ - *andptr++ = t[0]; - asmando(&p->to, t[1]); - break; - - case 2: /* m,r */ - *andptr++ = t[0]; - asmando(&p->from, t[1]); - break; - - case 3: /* r,m - 2op */ - *andptr++ = t[0]; - *andptr++ = t[1]; - asmando(&p->to, t[2]); - rexflag |= regrex[p->from.type] & (Rxr|0x40); - break; - - case 4: /* m,r - 2op */ - *andptr++ = t[0]; - *andptr++ = t[1]; - asmando(&p->from, t[2]); - rexflag |= regrex[p->to.type] & (Rxr|0x40); - break; - - case 5: /* load full pointer, trash heap */ - if(t[0]) - *andptr++ = t[0]; - switch(p->to.index) { - default: - goto bad; - case D_DS: - *andptr++ = 0xc5; - break; - case D_SS: - *andptr++ = 0x0f; - *andptr++ = 0xb2; - break; - case D_ES: - *andptr++ = 0xc4; - break; - case D_FS: - *andptr++ = 0x0f; - *andptr++ = 0xb4; - break; - case D_GS: - *andptr++ = 0x0f; - *andptr++ = 0xb5; - break; - } - asmand(&p->from, &p->to); - break; - - case 6: /* double shift */ - if(t[0] == Pw){ - if(p->mode != 64) - diag("asmins: illegal 64: %P", p); - rexflag |= Pw; - t++; - }else if(t[0] == Pe){ - *andptr++ = Pe; - t++; - } - z = p->from.type; - switch(z) { - default: - goto bad; - case D_CONST: - *andptr++ = 0x0f; - *andptr++ = t[0]; - asmandsz(&p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0); - *andptr++ = p->from.offset; - break; - case D_CL: - case D_CX: - *andptr++ = 0x0f; - *andptr++ = t[1]; - asmandsz(&p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0); - break; - } - break; - } -} - -void -asmins(Prog *p) -{ - int n, np, c; - Reloc *r; - - rexflag = 0; - andptr = and; - asmode = p->mode; - doasm(p); - if(rexflag){ - /* - * 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/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'. - */ - if(p->mode != 64) - diag("asmins: illegal in mode %d: %P", p->mode, p); - n = andptr - and; - for(np = 0; np < n; np++) { - c = and[np]; - if(c != 0xf2 && c != 0xf3 && (c < 0x64 || c > 0x67) && c != 0x2e && c != 0x3e && c != 0x26) - break; - } - memmove(and+np+1, and+np, n-np); - and[np] = 0x40 | rexflag; - andptr++; - } - n = andptr - and; - for(r=cursym->r+cursym->nr; r-- > cursym->r; ) { - if(r->off < p->pc) - break; - if(rexflag) - r->off++; - if(r->type == D_PCREL) - r->add -= p->pc + n - (r->off + r->siz); - } -} diff --git a/src/cmd/8a/a.h b/src/cmd/8a/a.h index c5c22d7ba..adc388ca9 100644 --- a/src/cmd/8a/a.h +++ b/src/cmd/8a/a.h @@ -29,9 +29,9 @@ // THE SOFTWARE. #include +#include #include "../8l/8.out.h" - #ifndef EXTERN #define EXTERN extern #endif @@ -45,10 +45,8 @@ typedef struct Sym Sym; typedef struct Ref Ref; -typedef struct Gen Gen; typedef struct Io Io; -typedef struct Hist Hist; -typedef struct Gen2 Gen2; +typedef struct Addr2 Addr2; #define MAXALIGN 7 #define FPCHIP 1 @@ -97,37 +95,11 @@ struct Io }; #define I ((Io*)0) -EXTERN struct -{ - Sym* sym; - short type; -} h[NSYM]; - -struct Gen -{ - double dval; - char sval[8]; - int32 offset; - int32 offset2; - Sym* sym; - short type; - short index; - short scale; -}; -struct Gen2 -{ - Gen from; - Gen to; -}; - -struct Hist +struct Addr2 { - Hist* link; - char* name; - int32 line; - int32 offset; + Addr from; + Addr to; }; -#define H ((Hist*)0) enum { @@ -137,14 +109,11 @@ enum CPREPROC, }; - -EXTERN char debug[256]; +EXTERN int debug[256]; EXTERN Sym* hash[NHASH]; EXTERN char** Dlist; EXTERN int nDlist; -EXTERN Hist* ehist; EXTERN int newflag; -EXTERN Hist* hist; EXTERN char* hunk; EXTERN char** include; EXTERN Io* iofree; @@ -155,10 +124,9 @@ EXTERN int nerrors; EXTERN int32 nhunk; EXTERN int ninclude; EXTERN int32 nsymb; -EXTERN Gen nullgen; +EXTERN Addr nullgen; EXTERN char* outfile; EXTERN int pass; -EXTERN char* pathname; EXTERN int32 pc; EXTERN int peekc; EXTERN int32 stmtline; @@ -168,6 +136,8 @@ EXTERN int thechar; EXTERN char* thestring; EXTERN int32 thunk; EXTERN Biobuf obuf; +EXTERN Link* ctxt; +EXTERN Biobuf bstdout; void* alloc(int32); void* allocn(void*, int32, int32); @@ -188,12 +158,9 @@ void cinit(void); void checkscale(int); void pinit(char*); void cclean(void); -int isreg(Gen*); -void outcode(int, Gen2*); +int isreg(Addr*); +void outcode(int, Addr2*); void outhist(void); -void zaddr(Gen*, int); -void zname(char*, int, int); -void ieeedtod(Ieee*, double); int filbuf(void); Sym* getsym(void); void domacro(void); diff --git a/src/cmd/8a/a.y b/src/cmd/8a/a.y index 13ccc985b..d7ff623da 100644 --- a/src/cmd/8a/a.y +++ b/src/cmd/8a/a.y @@ -44,8 +44,8 @@ } con2; double dval; char sval[8]; - Gen gen; - Gen2 gen2; + Addr addr; + Addr2 addr2; } %left '|' %left '^' @@ -62,9 +62,9 @@ %token LNAME LLAB LVAR %type con expr pointer offset %type con2 -%type mem imm imm2 reg nam rel rem rim rom omem nmem -%type nonnon nonrel nonrem rimnon rimrem remrim -%type spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8 spec9 spec10 spec11 spec12 +%type mem imm imm2 reg nam rel rem rim rom omem nmem +%type nonnon nonrel nonrem rimnon rimrem remrim +%type spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8 spec9 spec10 spec11 spec12 %% prog: | prog @@ -366,14 +366,12 @@ rel: if(pass == 2) yyerror("undefined label: %s", $1->name); $$.type = D_BRANCH; - $$.sym = $1; $$.offset = $2; } | LLAB offset { $$ = nullgen; $$.type = D_BRANCH; - $$.sym = $1; $$.offset = $1->value + $2; } @@ -431,31 +429,31 @@ imm: { $$ = nullgen; $$.type = D_SCONST; - memcpy($$.sval, $2, sizeof($$.sval)); + memcpy($$.u.sval, $2, sizeof($$.u.sval)); } | '$' LFCONST { $$ = nullgen; $$.type = D_FCONST; - $$.dval = $2; + $$.u.dval = $2; } | '$' '(' LFCONST ')' { $$ = nullgen; $$.type = D_FCONST; - $$.dval = $3; + $$.u.dval = $3; } | '$' '(' '-' LFCONST ')' { $$ = nullgen; $$.type = D_FCONST; - $$.dval = -$4; + $$.u.dval = -$4; } | '$' '-' LFCONST { $$ = nullgen; $$.type = D_FCONST; - $$.dval = -$3; + $$.u.dval = -$3; } imm2: @@ -590,14 +588,14 @@ nam: { $$ = nullgen; $$.type = $4; - $$.sym = $1; + $$.sym = linklookup(ctxt, $1->name, 0); $$.offset = $2; } | LNAME '<' '>' offset '(' LSB ')' { $$ = nullgen; $$.type = D_STATIC; - $$.sym = $1; + $$.sym = linklookup(ctxt, $1->name, 1); $$.offset = $4; } diff --git a/src/cmd/8a/lex.c b/src/cmd/8a/lex.c index f2ccc3361..32c099b75 100644 --- a/src/cmd/8a/lex.c +++ b/src/cmd/8a/lex.c @@ -57,56 +57,75 @@ pathchar(void) return '/'; } +int +Lconv(Fmt *fp) +{ + return linklinefmt(ctxt, fp); +} + +void +dodef(char *p) +{ + if(nDlist%8 == 0) + Dlist = allocn(Dlist, nDlist*sizeof(char *), + 8*sizeof(char *)); + Dlist[nDlist++] = p; +} + +void +usage(void) +{ + print("usage: %ca [options] file.c...\n", thechar); + flagprint(1); + errorexit(); +} void main(int argc, char *argv[]) { char *p; - int c; thechar = '8'; thestring = "386"; + ctxt = linknew(&link386); + ctxt->diag = yyerror; + ctxt->bso = &bstdout; + Binit(&bstdout, 1, OWRITE); + listinit8(); + fmtinstall('L', Lconv); + + // Allow GOARCH=thestring or GOARCH=thestringsuffix, + // but not other values. + p = getgoarch(); + if(strncmp(p, thestring, strlen(thestring)) != 0) + sysfatal("cannot use %cc with GOARCH=%s", thechar, p); + ensuresymb(NSYMB); memset(debug, 0, sizeof(debug)); cinit(); outfile = 0; setinclude("."); - ARGBEGIN { - default: - c = ARGC(); - if(c >= 0 && c < sizeof(debug)) - debug[c] = 1; - break; - - case 'o': - outfile = ARGF(); - break; - - case 'D': - p = ARGF(); - if(p) { - if (nDlist%8 == 0) - Dlist = allocn(Dlist, nDlist*sizeof(char *), - 8*sizeof(char *)); - Dlist[nDlist++] = p; - } - break; - - case 'I': - p = ARGF(); - setinclude(p); - break; - } ARGEND - if(*argv == 0) { - print("usage: %ca [-options] file.s\n", thechar); - errorexit(); - } + + flagfn1("D", "name[=value]: add #define", dodef); + flagfn1("I", "dir: add dir to include path", setinclude); + flagcount("S", "print assembly and machine code", &debug['S']); + flagcount("m", "debug preprocessor macros", &debug['m']); + flagstr("o", "file: set output file", &outfile); + flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath); + + flagparse(&argc, &argv, usage); + ctxt->debugasm = debug['S']; + + if(argc < 1) + usage(); if(argc > 1){ print("can't assemble multiple files\n"); errorexit(); } + if(assemble(argv[0])) errorexit(); + Bflush(&bstdout); exits(0); } @@ -145,30 +164,22 @@ assemble(char *file) errorexit(); } Binit(&obuf, of, OWRITE); - - pass = 1; - pinit(file); - - Bprint(&obuf, "go object %s %s %s\n", getgoos(), thestring, getgoversion()); - - for(i=0; itype = itab[i].type; s->value = itab[i].value; } - - pathname = allocn(pathname, 0, 100); - if(getwd(pathname, 99) == 0) { - pathname = allocn(pathname, 100, 900); - if(getwd(pathname, 999) == 0) - strcpy(pathname, "/???"); - } } void @@ -868,252 +867,43 @@ syminit(Sym *s) void cclean(void) { - Gen2 g2; + Addr2 g2; g2.from = nullgen; g2.to = nullgen; outcode(AEND, &g2); - Bflush(&obuf); } -void -zname(char *n, int t, int s) -{ - - BPUTLE2(&obuf, ANAME); /* as(2) */ - BPUTC(&obuf, t); /* type */ - BPUTC(&obuf, s); /* sym */ - while(*n) { - BPUTC(&obuf, *n); - n++; - } - BPUTC(&obuf, 0); -} +static Prog *lastpc; void -zaddr(Gen *a, int s) +outcode(int a, Addr2 *g2) { - int32 l; - int i, t; - char *n; - Ieee e; - - t = 0; - if(a->index != D_NONE || a->scale != 0) - t |= T_INDEX; - if(a->offset != 0) - t |= T_OFFSET; - if(s != 0) - t |= T_SYM; - - switch(a->type) { - default: - t |= T_TYPE; - break; - case D_FCONST: - t |= T_FCONST; - break; - case D_CONST2: - t |= T_OFFSET|T_OFFSET2; - break; - case D_SCONST: - t |= T_SCONST; - break; - case D_NONE: - break; - } - BPUTC(&obuf, t); - - if(t & T_INDEX) { /* implies index, scale */ - BPUTC(&obuf, a->index); - BPUTC(&obuf, a->scale); - } - if(t & T_OFFSET) { /* implies offset */ - l = a->offset; - BPUTLE4(&obuf, l); - } - if(t & T_OFFSET2) { - l = a->offset2; - BPUTLE4(&obuf, l); - } - if(t & T_SYM) /* implies sym */ - BPUTC(&obuf, s); - if(t & T_FCONST) { - ieeedtod(&e, a->dval); - BPUTLE4(&obuf, e.l); - BPUTLE4(&obuf, e.h); - return; - } - if(t & T_SCONST) { - n = a->sval; - for(i=0; itype); -} - -void -outcode(int a, Gen2 *g2) -{ - int sf, st, t; - Sym *s; - + Prog *p; + Plist *pl; + if(pass == 1) goto out; -jackpot: - sf = 0; - s = g2->from.sym; - while(s != S) { - sf = s->sym; - if(sf < 0 || sf >= NSYM) - sf = 0; - t = g2->from.type; - if(t == D_ADDR) - t = g2->from.index; - if(h[sf].type == t) - if(h[sf].sym == s) - break; - zname(s->name, t, sym); - s->sym = sym; - h[sym].sym = s; - h[sym].type = t; - sf = sym; - sym++; - if(sym >= NSYM) - sym = 1; - break; - } - st = 0; - s = g2->to.sym; - while(s != S) { - st = s->sym; - if(st < 0 || st >= NSYM) - st = 0; - t = g2->to.type; - if(t == D_ADDR) - t = g2->to.index; - if(h[st].type == t) - if(h[st].sym == s) - break; - zname(s->name, t, sym); - s->sym = sym; - h[sym].sym = s; - h[sym].type = t; - st = sym; - sym++; - if(sym >= NSYM) - sym = 1; - if(st == sf) - goto jackpot; - break; - } - BPUTLE2(&obuf, a); - BPUTLE4(&obuf, stmtline); - zaddr(&g2->from, sf); - zaddr(&g2->to, st); + p = malloc(sizeof *p); + memset(p, 0, sizeof *p); + p->as = a; + p->lineno = stmtline; + p->from = g2->from; + p->to = g2->to; + p->pc = pc; + + if(lastpc == nil) { + pl = linknewplist(ctxt); + pl->firstpc = p; + } else + lastpc->link = p; + lastpc = p; out: if(a != AGLOBL && a != ADATA) pc++; } -void -outhist(void) -{ - Gen g; - Hist *h; - char *p, *q, *op, c; - int n; - char *tofree; - static int first = 1; - static char *goroot, *goroot_final; - - if(first) { - // Decide whether we need to rewrite paths from $GOROOT to $GOROOT_FINAL. - first = 0; - goroot = getenv("GOROOT"); - goroot_final = getenv("GOROOT_FINAL"); - if(goroot == nil) - goroot = ""; - if(goroot_final == nil) - goroot_final = goroot; - if(strcmp(goroot, goroot_final) == 0) { - goroot = nil; - goroot_final = nil; - } - } - - tofree = nil; - - g = nullgen; - c = pathchar(); - for(h = hist; h != H; h = h->link) { - p = h->name; - if(p != nil && goroot != nil) { - n = strlen(goroot); - if(strncmp(p, goroot, strlen(goroot)) == 0 && p[n] == '/') { - tofree = smprint("%s%s", goroot_final, p+n); - p = tofree; - } - } - op = 0; - if(systemtype(Windows) && p && p[1] == ':'){ - c = p[2]; - } else if(p && p[0] != c && h->offset == 0 && pathname){ - if(systemtype(Windows) && pathname[1] == ':') { - op = p; - p = pathname; - c = p[2]; - } else if(pathname[0] == c){ - op = p; - p = pathname; - } - } - while(p) { - q = strchr(p, c); - if(q) { - n = q-p; - if(n == 0){ - n = 1; /* leading "/" */ - *p = '/'; /* don't emit "\" on windows */ - } - q++; - } else { - n = strlen(p); - q = 0; - } - if(n) { - BPUTLE2(&obuf, ANAME); - BPUTC(&obuf, D_FILE); /* type */ - BPUTC(&obuf, 1); /* sym */ - BPUTC(&obuf, '<'); - Bwrite(&obuf, p, n); - BPUTC(&obuf, 0); - } - p = q; - if(p == 0 && op) { - p = op; - op = 0; - } - } - g.offset = h->offset; - - BPUTLE2(&obuf, AHISTORY); - BPUTLE4(&obuf, h->line); - zaddr(&nullgen, 0); - zaddr(&g, 0); - - if(tofree) { - free(tofree); - tofree = nil; - } - } -} - #include "../cc/lexbody" #include "../cc/macbody" diff --git a/src/cmd/8a/y.tab.c b/src/cmd/8a/y.tab.c index aec4856f6..f48c9fe1f 100644 --- a/src/cmd/8a/y.tab.c +++ b/src/cmd/8a/y.tab.c @@ -1,21 +1,24 @@ -/* A Bison parser, made by GNU Bison 2.5. */ +/* A Bison parser, made by GNU Bison 2.3. */ -/* Bison implementation for Yacc-like parsers in C - - Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify +/* Skeleton implementation for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - + the Free Software Foundation; either version 2, or (at your option) + any later version. + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License - along with this program. If not, see . */ + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work @@ -26,7 +29,7 @@ special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. - + This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ @@ -44,7 +47,7 @@ #define YYBISON 1 /* Bison version. */ -#define YYBISON_VERSION "2.5" +#define YYBISON_VERSION "2.3" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -52,51 +55,11 @@ /* Pure parsers. */ #define YYPURE 0 -/* Push parsers. */ -#define YYPUSH 0 - -/* Pull parsers. */ -#define YYPULL 1 - /* Using locations. */ #define YYLSP_NEEDED 0 -/* Copy the first part of user declarations. */ - -/* Line 268 of yacc.c */ -#line 31 "a.y" - -#include -#include /* if we don't, bison will, and a.h re-#defines getc */ -#include -#include "a.h" -#include "../../pkg/runtime/funcdata.h" - - -/* Line 268 of yacc.c */ -#line 80 "y.tab.c" - -/* Enabling traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif - -/* Enabling verbose error messages. */ -#ifdef YYERROR_VERBOSE -# undef YYERROR_VERBOSE -# define YYERROR_VERBOSE 1 -#else -# define YYERROR_VERBOSE 0 -#endif - -/* Enabling the token table. */ -#ifndef YYTOKEN_TABLE -# define YYTOKEN_TABLE 0 -#endif - - /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE @@ -176,13 +139,38 @@ +/* Copy the first part of user declarations. */ +#line 31 "a.y" + +#include +#include /* if we don't, bison will, and a.h re-#defines getc */ +#include +#include "a.h" +#include "../../pkg/runtime/funcdata.h" + + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE -{ - -/* Line 293 of yacc.c */ #line 38 "a.y" - +{ Sym *sym; int32 lval; struct { @@ -191,25 +179,24 @@ typedef union YYSTYPE } con2; double dval; char sval[8]; - Gen gen; - Gen2 gen2; - - - -/* Line 293 of yacc.c */ -#line 201 "y.tab.c" -} YYSTYPE; -# define YYSTYPE_IS_TRIVIAL 1 + Addr addr; + Addr2 addr2; +} +/* Line 193 of yacc.c. */ +#line 187 "y.tab.c" + YYSTYPE; # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 #endif + /* Copy the second part of user declarations. */ -/* Line 343 of yacc.c */ -#line 213 "y.tab.c" +/* Line 216 of yacc.c. */ +#line 200 "y.tab.c" #ifdef short # undef short @@ -284,14 +271,14 @@ typedef short int yytype_int16; #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static int -YYID (int yyi) +YYID (int i) #else static int -YYID (yyi) - int yyi; +YYID (i) + int i; #endif { - return yyi; + return i; } #endif @@ -312,11 +299,11 @@ YYID (yyi) # define alloca _alloca # else # define YYSTACK_ALLOC alloca -# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ +# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) # include /* INFRINGES ON USER NAME SPACE */ -# ifndef EXIT_SUCCESS -# define EXIT_SUCCESS 0 +# ifndef _STDLIB_H +# define _STDLIB_H 1 # endif # endif # endif @@ -339,24 +326,24 @@ YYID (yyi) # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif -# if (defined __cplusplus && ! defined EXIT_SUCCESS \ +# if (defined __cplusplus && ! defined _STDLIB_H \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ -# ifndef EXIT_SUCCESS -# define EXIT_SUCCESS 0 +# ifndef _STDLIB_H +# define _STDLIB_H 1 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc -# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ +# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free -# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ +# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif @@ -372,9 +359,9 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */ /* A type that is properly aligned for any stack member. */ union yyalloc { - yytype_int16 yyss_alloc; - YYSTYPE yyvs_alloc; -}; + yytype_int16 yyss; + YYSTYPE yyvs; + }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) @@ -385,27 +372,6 @@ union yyalloc ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) -# define YYCOPY_NEEDED 1 - -/* Relocate STACK from its old location to the new one. The - local variables YYSIZE and YYSTACKSIZE give the old and new number of - elements in the stack, and YYPTR gives the new location of the - stack. Advance YYPTR to a properly aligned location for the next - stack. */ -# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ - do \ - { \ - YYSIZE_T yynewbytes; \ - YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ - Stack = &yyptr->Stack_alloc; \ - yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ - yyptr += yynewbytes / sizeof (*yyptr); \ - } \ - while (YYID (0)) - -#endif - -#if defined YYCOPY_NEEDED && YYCOPY_NEEDED /* Copy COUNT objects from FROM to TO. The source and destination do not overlap. */ # ifndef YYCOPY @@ -423,7 +389,24 @@ union yyalloc while (YYID (0)) # endif # endif -#endif /* !YYCOPY_NEEDED */ + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack, Stack, yysize); \ + Stack = &yyptr->Stack; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif /* YYFINAL -- State number of the termination state. */ #define YYFINAL 2 @@ -564,13 +547,13 @@ static const yytype_uint16 yyrline[] = 175, 180, 185, 192, 200, 205, 213, 218, 223, 232, 233, 236, 241, 251, 256, 266, 271, 276, 283, 288, 296, 304, 314, 323, 334, 335, 338, 339, 340, 344, - 348, 349, 350, 353, 354, 357, 363, 372, 381, 386, - 391, 396, 401, 406, 413, 419, 430, 436, 442, 448, - 454, 462, 471, 476, 481, 486, 493, 494, 497, 503, - 509, 515, 524, 533, 542, 547, 552, 558, 566, 576, - 580, 589, 596, 605, 608, 612, 618, 619, 623, 626, - 627, 631, 635, 639, 643, 649, 650, 654, 658, 662, - 666, 670, 674, 678, 682, 686 + 348, 349, 350, 353, 354, 357, 363, 371, 379, 384, + 389, 394, 399, 404, 411, 417, 428, 434, 440, 446, + 452, 460, 469, 474, 479, 484, 491, 492, 495, 501, + 507, 513, 522, 531, 540, 545, 550, 556, 564, 574, + 578, 587, 594, 603, 606, 610, 616, 617, 621, 624, + 625, 629, 633, 637, 641, 647, 648, 652, 656, 660, + 664, 668, 672, 676, 680, 684 }; #endif @@ -585,12 +568,12 @@ static const char *const yytname[] = "LTYPEM", "LTYPEI", "LTYPEG", "LTYPEXC", "LTYPEX", "LTYPEPC", "LTYPEF", "LCONST", "LFP", "LPC", "LSB", "LBREG", "LLREG", "LSREG", "LFREG", "LXREG", "LFCONST", "LSCONST", "LSP", "LNAME", "LLAB", "LVAR", "':'", - "';'", "'='", "','", "'('", "')'", "'$'", "'~'", "$accept", "prog", - "$@1", "line", "$@2", "$@3", "inst", "nonnon", "rimrem", "remrim", - "rimnon", "nonrem", "nonrel", "spec1", "spec2", "spec3", "spec4", - "spec5", "spec6", "spec7", "spec8", "spec9", "spec10", "spec11", - "spec12", "rem", "rom", "rim", "rel", "reg", "imm", "imm2", "con2", - "mem", "omem", "nmem", "nam", "offset", "pointer", "con", "expr", 0 + "';'", "'='", "','", "'('", "')'", "'$'", "'~'", "$accept", "prog", "@1", + "line", "@2", "@3", "inst", "nonnon", "rimrem", "remrim", "rimnon", + "nonrem", "nonrel", "spec1", "spec2", "spec3", "spec4", "spec5", "spec6", + "spec7", "spec8", "spec9", "spec10", "spec11", "spec12", "rem", "rom", + "rim", "rel", "reg", "imm", "imm2", "con2", "mem", "omem", "nmem", "nam", + "offset", "pointer", "con", "expr", 0 }; #endif @@ -646,8 +629,8 @@ static const yytype_uint8 yyr2[] = 3, 4, 4, 3, 3, 3 }; -/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM. - Performed when YYTABLE doesn't specify something else to do. Zero +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero means the default is an error. */ static const yytype_uint8 yydefact[] = { @@ -738,7 +721,8 @@ static const yytype_int16 yypgoto[] = /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which - number is the opposite. If YYTABLE_NINF, syntax error. */ + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ #define YYTABLE_NINF -1 static const yytype_uint16 yytable[] = { @@ -799,12 +783,6 @@ static const yytype_uint16 yytable[] = 170, 171, 172, 173, 174, 175, 176 }; -#define yypact_value_is_default(yystate) \ - ((yystate) == (-104)) - -#define yytable_value_is_error(yytable_value) \ - YYID (0) - static const yytype_int16 yycheck[] = { 10, 10, 10, 13, 0, 13, 8, 13, 11, 10, @@ -910,18 +888,9 @@ static const yytype_uint8 yystos[] = /* Like YYERROR except do call yyerror. This remains here temporarily to ease the transition to the new meaning of YYERROR, for GCC. - Once GCC version 2 has supplanted version 1, this can go. However, - YYFAIL appears to be in use. Nevertheless, it is formally deprecated - in Bison 2.4.2's NEWS entry, where a plan to phase it out is - discussed. */ + Once GCC version 2 has supplanted version 1, this can go. */ #define YYFAIL goto yyerrlab -#if defined YYFAIL - /* This is here to suppress warnings from the GCC cpp's - -Wunused-macros. Normally we don't worry about that warning, but - some users do, and we want to make it easy for users to remove - YYFAIL uses, which will produce warnings from Bison 2.5. */ -#endif #define YYRECOVERING() (!!yyerrstatus) @@ -931,6 +900,7 @@ do \ { \ yychar = (Token); \ yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ YYPOPSTACK (1); \ goto yybackup; \ } \ @@ -972,10 +942,19 @@ while (YYID (0)) #endif -/* This macro is provided for backward compatibility. */ +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ #ifndef YY_LOCATION_PRINT -# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif #endif @@ -1079,20 +1058,17 @@ yy_symbol_print (yyoutput, yytype, yyvaluep) #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void -yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +yy_stack_print (yytype_int16 *bottom, yytype_int16 *top) #else static void -yy_stack_print (yybottom, yytop) - yytype_int16 *yybottom; - yytype_int16 *yytop; +yy_stack_print (bottom, top) + yytype_int16 *bottom; + yytype_int16 *top; #endif { YYFPRINTF (stderr, "Stack now"); - for (; yybottom <= yytop; yybottom++) - { - int yybot = *yybottom; - YYFPRINTF (stderr, " %d", yybot); - } + for (; bottom <= top; ++bottom) + YYFPRINTF (stderr, " %d", *bottom); YYFPRINTF (stderr, "\n"); } @@ -1126,11 +1102,11 @@ yy_reduce_print (yyvsp, yyrule) /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { - YYFPRINTF (stderr, " $%d = ", yyi + 1); + fprintf (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], &(yyvsp[(yyi + 1) - (yynrhs)]) ); - YYFPRINTF (stderr, "\n"); + fprintf (stderr, "\n"); } } @@ -1167,6 +1143,7 @@ int yydebug; # define YYMAXDEPTH 10000 #endif + #if YYERROR_VERBOSE @@ -1269,142 +1246,115 @@ yytnamerr (char *yyres, const char *yystr) } # endif -/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message - about the unexpected token YYTOKEN for the state stack whose top is - YYSSP. - - Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is - not large enough to hold the message. In that case, also set - *YYMSG_ALLOC to the required number of bytes. Return 2 if the - required number of bytes is too large to store. */ -static int -yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, - yytype_int16 *yyssp, int yytoken) +/* Copy into YYRESULT an error message about the unexpected token + YYCHAR while in state YYSTATE. Return the number of bytes copied, + including the terminating null byte. If YYRESULT is null, do not + copy anything; just return the number of bytes that would be + copied. As a special case, return 0 if an ordinary "syntax error" + message will do. Return YYSIZE_MAXIMUM if overflow occurs during + size calculation. */ +static YYSIZE_T +yysyntax_error (char *yyresult, int yystate, int yychar) { - YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]); - YYSIZE_T yysize = yysize0; - YYSIZE_T yysize1; - enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; - /* Internationalized format string. */ - const char *yyformat = 0; - /* Arguments of yyformat. */ - char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; - /* Number of reported tokens (one for the "unexpected", one per - "expected"). */ - int yycount = 0; - - /* There are many possibilities here to consider: - - Assume YYFAIL is not used. It's too flawed to consider. See - - for details. YYERROR is fine as it does not invoke this - function. - - If this state is a consistent state with a default action, then - the only way this function was invoked is if the default action - is an error action. In that case, don't check for expected - tokens because there are none. - - The only way there can be no lookahead present (in yychar) is if - this state is a consistent state with a default action. Thus, - detecting the absence of a lookahead is sufficient to determine - that there is no unexpected or expected token to report. In that - case, just report a simple "syntax error". - - Don't assume there isn't a lookahead just because this state is a - consistent state with a default action. There might have been a - previous inconsistent state, consistent state with a non-default - action, or user semantic action that manipulated yychar. - - Of course, the expected token list depends on states to have - correct lookahead information, and it depends on the parser not - to perform extra reductions after fetching a lookahead from the - scanner and before detecting a syntax error. Thus, state merging - (from LALR or IELR) and default reductions corrupt the expected - token list. However, the list is correct for canonical LR with - one exception: it will still contain any token that will not be - accepted due to an error action in a later state. - */ - if (yytoken != YYEMPTY) - { - int yyn = yypact[*yyssp]; - yyarg[yycount++] = yytname[yytoken]; - if (!yypact_value_is_default (yyn)) - { - /* Start YYX at -YYN if negative to avoid negative indexes in - YYCHECK. In other words, skip the first -YYN actions for - this state because they are default actions. */ - int yyxbegin = yyn < 0 ? -yyn : 0; - /* Stay within bounds of both yycheck and yytname. */ - int yychecklim = YYLAST - yyn + 1; - int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; - int yyx; - - for (yyx = yyxbegin; yyx < yyxend; ++yyx) - if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR - && !yytable_value_is_error (yytable[yyx + yyn])) - { - if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) - { - yycount = 1; - yysize = yysize0; - break; - } - yyarg[yycount++] = yytname[yyx]; - yysize1 = yysize + yytnamerr (0, yytname[yyx]); - if (! (yysize <= yysize1 - && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) - return 2; - yysize = yysize1; - } - } - } + int yyn = yypact[yystate]; - switch (yycount) - { -# define YYCASE_(N, S) \ - case N: \ - yyformat = S; \ - break - YYCASE_(0, YY_("syntax error")); - YYCASE_(1, YY_("syntax error, unexpected %s")); - YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); - YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); - YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); - YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); -# undef YYCASE_ - } + if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) + return 0; + else + { + int yytype = YYTRANSLATE (yychar); + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + int yysize_overflow = 0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int yyx; + +# if 0 + /* This is so xgettext sees the translatable formats that are + constructed on the fly. */ + YY_("syntax error, unexpected %s"); + YY_("syntax error, unexpected %s, expecting %s"); + YY_("syntax error, unexpected %s, expecting %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); +# endif + char *yyfmt; + char const *yyf; + static char const yyunexpected[] = "syntax error, unexpected %s"; + static char const yyexpecting[] = ", expecting %s"; + static char const yyor[] = " or %s"; + char yyformat[sizeof yyunexpected + + sizeof yyexpecting - 1 + + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) + * (sizeof yyor - 1))]; + char const *yyprefix = yyexpecting; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 1; + + yyarg[0] = yytname[yytype]; + yyfmt = yystpcpy (yyformat, yyunexpected); + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + yyformat[sizeof yyunexpected - 1] = '\0'; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + yyfmt = yystpcpy (yyfmt, yyprefix); + yyprefix = yyor; + } - yysize1 = yysize + yystrlen (yyformat); - if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) - return 2; - yysize = yysize1; + yyf = YY_(yyformat); + yysize1 = yysize + yystrlen (yyf); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; - if (*yymsg_alloc < yysize) - { - *yymsg_alloc = 2 * yysize; - if (! (yysize <= *yymsg_alloc - && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) - *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; - return 1; - } + if (yysize_overflow) + return YYSIZE_MAXIMUM; - /* Avoid sprintf, as that infringes on the user's name space. - Don't have undefined behavior even if the translation - produced a string with the wrong number of "%s"s. */ - { - char *yyp = *yymsg; - int yyi = 0; - while ((*yyp = *yyformat) != '\0') - if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) - { - yyp += yytnamerr (yyp, yyarg[yyi++]); - yyformat += 2; - } - else - { - yyp++; - yyformat++; - } - } - return 0; + if (yyresult) + { + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + char *yyp = yyresult; + int yyi = 0; + while ((*yyp = *yyf) != '\0') + { + if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyf += 2; + } + else + { + yyp++; + yyf++; + } + } + } + return yysize; + } } #endif /* YYERROR_VERBOSE */ + /*-----------------------------------------------. | Release the memory associated to this symbol. | @@ -1436,9 +1386,10 @@ yydestruct (yymsg, yytype, yyvaluep) break; } } - + /* Prevent warnings from -Wmissing-prototypes. */ + #ifdef YYPARSE_PARAM #if defined __STDC__ || defined __cplusplus int yyparse (void *YYPARSE_PARAM); @@ -1454,16 +1405,18 @@ int yyparse (); #endif /* ! YYPARSE_PARAM */ -/* The lookahead symbol. */ + +/* The look-ahead symbol. */ int yychar; -/* The semantic value of the lookahead symbol. */ +/* The semantic value of the look-ahead symbol. */ YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; + /*----------. | yyparse. | `----------*/ @@ -1490,37 +1443,14 @@ yyparse () #endif #endif { - int yystate; - /* Number of tokens to shift before error messages enabled. */ - int yyerrstatus; - - /* The stacks and their tools: - `yyss': related to states. - `yyvs': related to semantic values. - - Refer to the stacks thru separate pointers, to allow yyoverflow - to reallocate them elsewhere. */ - - /* The state stack. */ - yytype_int16 yyssa[YYINITDEPTH]; - yytype_int16 *yyss; - yytype_int16 *yyssp; - - /* The semantic value stack. */ - YYSTYPE yyvsa[YYINITDEPTH]; - YYSTYPE *yyvs; - YYSTYPE *yyvsp; - - YYSIZE_T yystacksize; - + + int yystate; int yyn; int yyresult; - /* Lookahead token as an internal (translated) token number. */ - int yytoken; - /* The variables used to return semantic value and location from the - action routines. */ - YYSTYPE yyval; - + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Look-ahead token as an internal (translated) token number. */ + int yytoken = 0; #if YYERROR_VERBOSE /* Buffer for error messages, and its allocated size. */ char yymsgbuf[128]; @@ -1528,28 +1458,51 @@ yyparse () YYSIZE_T yymsg_alloc = sizeof yymsgbuf; #endif + /* Three stacks and their tools: + `yyss': related to states, + `yyvs': related to semantic values, + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss = yyssa; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + YYSTYPE *yyvsp; + + + #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + YYSIZE_T yystacksize = YYINITDEPTH; + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + + /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; - yytoken = 0; - yyss = yyssa; - yyvs = yyvsa; - yystacksize = YYINITDEPTH; - YYDPRINTF ((stderr, "Starting parse\n")); yystate = 0; yyerrstatus = 0; yynerrs = 0; - yychar = YYEMPTY; /* Cause a token to be read. */ + yychar = YYEMPTY; /* Cause a token to be read. */ /* Initialize stack pointers. Waste one element of value and location stack so that they stay on the same level as the state stack. The wasted elements are never initialized. */ + yyssp = yyss; yyvsp = yyvs; @@ -1579,6 +1532,7 @@ yyparse () YYSTYPE *yyvs1 = yyvs; yytype_int16 *yyss1 = yyss; + /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might @@ -1586,6 +1540,7 @@ yyparse () yyoverflow (YY_("memory exhausted"), &yyss1, yysize * sizeof (*yyssp), &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); yyss = yyss1; @@ -1608,8 +1563,9 @@ yyparse () (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); if (! yyptr) goto yyexhaustedlab; - YYSTACK_RELOCATE (yyss_alloc, yyss); - YYSTACK_RELOCATE (yyvs_alloc, yyvs); + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); + # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); @@ -1620,6 +1576,7 @@ yyparse () yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; + YYDPRINTF ((stderr, "Stack size increased to %lu\n", (unsigned long int) yystacksize)); @@ -1629,9 +1586,6 @@ yyparse () YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - if (yystate == YYFINAL) - YYACCEPT; - goto yybackup; /*-----------. @@ -1640,16 +1594,16 @@ yyparse () yybackup: /* Do appropriate processing given the current state. Read a - lookahead token if we need one and don't already have one. */ + look-ahead token if we need one and don't already have one. */ - /* First try to decide what to do without reference to lookahead token. */ + /* First try to decide what to do without reference to look-ahead token. */ yyn = yypact[yystate]; - if (yypact_value_is_default (yyn)) + if (yyn == YYPACT_NINF) goto yydefault; - /* Not known => get a lookahead token if don't already have one. */ + /* Not known => get a look-ahead token if don't already have one. */ - /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token: ")); @@ -1675,22 +1629,26 @@ yybackup: yyn = yytable[yyn]; if (yyn <= 0) { - if (yytable_value_is_error (yyn)) - goto yyerrlab; + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; yyn = -yyn; goto yyreduce; } + if (yyn == YYFINAL) + YYACCEPT; + /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; - /* Shift the lookahead token. */ + /* Shift the look-ahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); - /* Discard the shifted token. */ - yychar = YYEMPTY; + /* Discard the shifted token unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; yystate = yyn; *++yyvsp = yylval; @@ -1730,8 +1688,6 @@ yyreduce: switch (yyn) { case 3: - -/* Line 1806 of yacc.c */ #line 71 "a.y" { stmtline = lineno; @@ -1739,8 +1695,6 @@ yyreduce: break; case 5: - -/* Line 1806 of yacc.c */ #line 78 "a.y" { if((yyvsp[(1) - (2)].sym)->value != pc) @@ -1750,8 +1704,6 @@ yyreduce: break; case 7: - -/* Line 1806 of yacc.c */ #line 85 "a.y" { (yyvsp[(1) - (2)].sym)->type = LLAB; @@ -1760,8 +1712,6 @@ yyreduce: break; case 12: - -/* Line 1806 of yacc.c */ #line 96 "a.y" { (yyvsp[(1) - (3)].sym)->type = LVAR; @@ -1770,8 +1720,6 @@ yyreduce: break; case 13: - -/* Line 1806 of yacc.c */ #line 101 "a.y" { if((yyvsp[(1) - (3)].sym)->value != (yyvsp[(3) - (3)].lval)) @@ -1781,586 +1729,462 @@ yyreduce: break; case 14: - -/* Line 1806 of yacc.c */ #line 106 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 15: - -/* Line 1806 of yacc.c */ #line 107 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 16: - -/* Line 1806 of yacc.c */ #line 108 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 17: - -/* Line 1806 of yacc.c */ #line 109 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 18: - -/* Line 1806 of yacc.c */ #line 110 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 19: - -/* Line 1806 of yacc.c */ #line 111 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 20: - -/* Line 1806 of yacc.c */ #line 112 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 21: - -/* Line 1806 of yacc.c */ #line 113 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 22: - -/* Line 1806 of yacc.c */ #line 114 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 23: - -/* Line 1806 of yacc.c */ #line 115 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 24: - -/* Line 1806 of yacc.c */ #line 116 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 25: - -/* Line 1806 of yacc.c */ #line 117 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 26: - -/* Line 1806 of yacc.c */ #line 118 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 27: - -/* Line 1806 of yacc.c */ #line 119 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 28: - -/* Line 1806 of yacc.c */ #line 120 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 29: - -/* Line 1806 of yacc.c */ #line 121 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 30: - -/* Line 1806 of yacc.c */ #line 122 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 31: - -/* Line 1806 of yacc.c */ #line 123 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); } + { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } break; case 32: - -/* Line 1806 of yacc.c */ #line 126 "a.y" { - (yyval.gen2).from = nullgen; - (yyval.gen2).to = nullgen; + (yyval.addr2).from = nullgen; + (yyval.addr2).to = nullgen; } break; case 33: - -/* Line 1806 of yacc.c */ #line 131 "a.y" { - (yyval.gen2).from = nullgen; - (yyval.gen2).to = nullgen; + (yyval.addr2).from = nullgen; + (yyval.addr2).to = nullgen; } break; case 34: - -/* Line 1806 of yacc.c */ #line 138 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (3)].gen); - (yyval.gen2).to = (yyvsp[(3) - (3)].gen); + (yyval.addr2).from = (yyvsp[(1) - (3)].addr); + (yyval.addr2).to = (yyvsp[(3) - (3)].addr); } break; case 35: - -/* Line 1806 of yacc.c */ #line 145 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (3)].gen); - (yyval.gen2).to = (yyvsp[(3) - (3)].gen); + (yyval.addr2).from = (yyvsp[(1) - (3)].addr); + (yyval.addr2).to = (yyvsp[(3) - (3)].addr); } break; case 36: - -/* Line 1806 of yacc.c */ #line 152 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (2)].gen); - (yyval.gen2).to = nullgen; + (yyval.addr2).from = (yyvsp[(1) - (2)].addr); + (yyval.addr2).to = nullgen; } break; case 37: - -/* Line 1806 of yacc.c */ #line 157 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (1)].gen); - (yyval.gen2).to = nullgen; + (yyval.addr2).from = (yyvsp[(1) - (1)].addr); + (yyval.addr2).to = nullgen; } break; case 38: - -/* Line 1806 of yacc.c */ #line 164 "a.y" { - (yyval.gen2).from = nullgen; - (yyval.gen2).to = (yyvsp[(2) - (2)].gen); + (yyval.addr2).from = nullgen; + (yyval.addr2).to = (yyvsp[(2) - (2)].addr); } break; case 39: - -/* Line 1806 of yacc.c */ #line 169 "a.y" { - (yyval.gen2).from = nullgen; - (yyval.gen2).to = (yyvsp[(1) - (1)].gen); + (yyval.addr2).from = nullgen; + (yyval.addr2).to = (yyvsp[(1) - (1)].addr); } break; case 40: - -/* Line 1806 of yacc.c */ #line 176 "a.y" { - (yyval.gen2).from = nullgen; - (yyval.gen2).to = (yyvsp[(2) - (2)].gen); + (yyval.addr2).from = nullgen; + (yyval.addr2).to = (yyvsp[(2) - (2)].addr); } break; case 41: - -/* Line 1806 of yacc.c */ #line 181 "a.y" { - (yyval.gen2).from = nullgen; - (yyval.gen2).to = (yyvsp[(1) - (1)].gen); + (yyval.addr2).from = nullgen; + (yyval.addr2).to = (yyvsp[(1) - (1)].addr); } break; case 42: - -/* Line 1806 of yacc.c */ #line 186 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (3)].gen); - (yyval.gen2).to = (yyvsp[(3) - (3)].gen); + (yyval.addr2).from = (yyvsp[(1) - (3)].addr); + (yyval.addr2).to = (yyvsp[(3) - (3)].addr); } break; case 43: - -/* Line 1806 of yacc.c */ #line 193 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (5)].gen); - (yyval.gen2).from.scale = (yyvsp[(3) - (5)].lval); - (yyval.gen2).to = (yyvsp[(5) - (5)].gen); + (yyval.addr2).from = (yyvsp[(1) - (5)].addr); + (yyval.addr2).from.scale = (yyvsp[(3) - (5)].lval); + (yyval.addr2).to = (yyvsp[(5) - (5)].addr); } break; case 44: - -/* Line 1806 of yacc.c */ #line 201 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (3)].gen); - (yyval.gen2).to = (yyvsp[(3) - (3)].gen); + (yyval.addr2).from = (yyvsp[(1) - (3)].addr); + (yyval.addr2).to = (yyvsp[(3) - (3)].addr); } break; case 45: - -/* Line 1806 of yacc.c */ #line 206 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (5)].gen); - (yyval.gen2).from.scale = (yyvsp[(3) - (5)].lval); - (yyval.gen2).to = (yyvsp[(5) - (5)].gen); + (yyval.addr2).from = (yyvsp[(1) - (5)].addr); + (yyval.addr2).from.scale = (yyvsp[(3) - (5)].lval); + (yyval.addr2).to = (yyvsp[(5) - (5)].addr); } break; case 46: - -/* Line 1806 of yacc.c */ #line 214 "a.y" { - (yyval.gen2).from = nullgen; - (yyval.gen2).to = (yyvsp[(2) - (2)].gen); + (yyval.addr2).from = nullgen; + (yyval.addr2).to = (yyvsp[(2) - (2)].addr); } break; case 47: - -/* Line 1806 of yacc.c */ #line 219 "a.y" { - (yyval.gen2).from = nullgen; - (yyval.gen2).to = (yyvsp[(1) - (1)].gen); + (yyval.addr2).from = nullgen; + (yyval.addr2).to = (yyvsp[(1) - (1)].addr); } break; case 48: - -/* Line 1806 of yacc.c */ #line 224 "a.y" { - (yyval.gen2).from = nullgen; - (yyval.gen2).to = (yyvsp[(2) - (2)].gen); - (yyval.gen2).to.index = (yyvsp[(2) - (2)].gen).type; - (yyval.gen2).to.type = D_INDIR+D_ADDR; + (yyval.addr2).from = nullgen; + (yyval.addr2).to = (yyvsp[(2) - (2)].addr); + (yyval.addr2).to.index = (yyvsp[(2) - (2)].addr).type; + (yyval.addr2).to.type = D_INDIR+D_ADDR; } break; case 51: - -/* Line 1806 of yacc.c */ #line 237 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (3)].gen); - (yyval.gen2).to = (yyvsp[(3) - (3)].gen); + (yyval.addr2).from = (yyvsp[(1) - (3)].addr); + (yyval.addr2).to = (yyvsp[(3) - (3)].addr); } break; case 52: - -/* Line 1806 of yacc.c */ #line 242 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (5)].gen); - (yyval.gen2).to = (yyvsp[(3) - (5)].gen); - if((yyval.gen2).from.index != D_NONE) + (yyval.addr2).from = (yyvsp[(1) - (5)].addr); + (yyval.addr2).to = (yyvsp[(3) - (5)].addr); + if((yyval.addr2).from.index != D_NONE) yyerror("dp shift with lhs index"); - (yyval.gen2).from.index = (yyvsp[(5) - (5)].lval); + (yyval.addr2).from.index = (yyvsp[(5) - (5)].lval); } break; case 53: - -/* Line 1806 of yacc.c */ #line 252 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (3)].gen); - (yyval.gen2).to = (yyvsp[(3) - (3)].gen); + (yyval.addr2).from = (yyvsp[(1) - (3)].addr); + (yyval.addr2).to = (yyvsp[(3) - (3)].addr); } break; case 54: - -/* Line 1806 of yacc.c */ #line 257 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (5)].gen); - (yyval.gen2).to = (yyvsp[(3) - (5)].gen); - if((yyval.gen2).to.index != D_NONE) + (yyval.addr2).from = (yyvsp[(1) - (5)].addr); + (yyval.addr2).to = (yyvsp[(3) - (5)].addr); + if((yyval.addr2).to.index != D_NONE) yyerror("dp move with lhs index"); - (yyval.gen2).to.index = (yyvsp[(5) - (5)].lval); + (yyval.addr2).to.index = (yyvsp[(5) - (5)].lval); } break; case 55: - -/* Line 1806 of yacc.c */ #line 267 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (2)].gen); - (yyval.gen2).to = nullgen; + (yyval.addr2).from = (yyvsp[(1) - (2)].addr); + (yyval.addr2).to = nullgen; } break; case 56: - -/* Line 1806 of yacc.c */ #line 272 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (1)].gen); - (yyval.gen2).to = nullgen; + (yyval.addr2).from = (yyvsp[(1) - (1)].addr); + (yyval.addr2).to = nullgen; } break; case 57: - -/* Line 1806 of yacc.c */ #line 277 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (3)].gen); - (yyval.gen2).to = (yyvsp[(3) - (3)].gen); + (yyval.addr2).from = (yyvsp[(1) - (3)].addr); + (yyval.addr2).to = (yyvsp[(3) - (3)].addr); } break; case 58: - -/* Line 1806 of yacc.c */ #line 284 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (3)].gen); - (yyval.gen2).to = (yyvsp[(3) - (3)].gen); + (yyval.addr2).from = (yyvsp[(1) - (3)].addr); + (yyval.addr2).to = (yyvsp[(3) - (3)].addr); } break; case 59: - -/* Line 1806 of yacc.c */ #line 289 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (5)].gen); - (yyval.gen2).from.scale = (yyvsp[(3) - (5)].lval); - (yyval.gen2).to = (yyvsp[(5) - (5)].gen); + (yyval.addr2).from = (yyvsp[(1) - (5)].addr); + (yyval.addr2).from.scale = (yyvsp[(3) - (5)].lval); + (yyval.addr2).to = (yyvsp[(5) - (5)].addr); } break; case 60: - -/* Line 1806 of yacc.c */ #line 297 "a.y" { - (yyval.gen2).from = (yyvsp[(1) - (5)].gen); - (yyval.gen2).to = (yyvsp[(3) - (5)].gen); - (yyval.gen2).to.offset = (yyvsp[(5) - (5)].lval); + (yyval.addr2).from = (yyvsp[(1) - (5)].addr); + (yyval.addr2).to = (yyvsp[(3) - (5)].addr); + (yyval.addr2).to.offset = (yyvsp[(5) - (5)].lval); } break; case 61: - -/* Line 1806 of yacc.c */ #line 305 "a.y" { - (yyval.gen2).from = (yyvsp[(3) - (5)].gen); - (yyval.gen2).to = (yyvsp[(5) - (5)].gen); - if((yyvsp[(1) - (5)].gen).type != D_CONST) + (yyval.addr2).from = (yyvsp[(3) - (5)].addr); + (yyval.addr2).to = (yyvsp[(5) - (5)].addr); + if((yyvsp[(1) - (5)].addr).type != D_CONST) yyerror("illegal constant"); - (yyval.gen2).to.offset = (yyvsp[(1) - (5)].gen).offset; + (yyval.addr2).to.offset = (yyvsp[(1) - (5)].addr).offset; } break; case 62: - -/* Line 1806 of yacc.c */ #line 315 "a.y" { - if((yyvsp[(1) - (3)].gen).type != D_CONST || (yyvsp[(3) - (3)].gen).type != D_CONST) + if((yyvsp[(1) - (3)].addr).type != D_CONST || (yyvsp[(3) - (3)].addr).type != D_CONST) yyerror("arguments to PCDATA must be integer constants"); - (yyval.gen2).from = (yyvsp[(1) - (3)].gen); - (yyval.gen2).to = (yyvsp[(3) - (3)].gen); + (yyval.addr2).from = (yyvsp[(1) - (3)].addr); + (yyval.addr2).to = (yyvsp[(3) - (3)].addr); } break; case 63: - -/* Line 1806 of yacc.c */ #line 324 "a.y" { - if((yyvsp[(1) - (3)].gen).type != D_CONST) + if((yyvsp[(1) - (3)].addr).type != D_CONST) yyerror("index for FUNCDATA must be integer constant"); - if((yyvsp[(3) - (3)].gen).type != D_EXTERN && (yyvsp[(3) - (3)].gen).type != D_STATIC) + if((yyvsp[(3) - (3)].addr).type != D_EXTERN && (yyvsp[(3) - (3)].addr).type != D_STATIC) yyerror("value for FUNCDATA must be symbol reference"); - (yyval.gen2).from = (yyvsp[(1) - (3)].gen); - (yyval.gen2).to = (yyvsp[(3) - (3)].gen); + (yyval.addr2).from = (yyvsp[(1) - (3)].addr); + (yyval.addr2).to = (yyvsp[(3) - (3)].addr); } break; case 68: - -/* Line 1806 of yacc.c */ #line 341 "a.y" { - (yyval.gen) = (yyvsp[(2) - (2)].gen); + (yyval.addr) = (yyvsp[(2) - (2)].addr); } break; case 69: - -/* Line 1806 of yacc.c */ #line 345 "a.y" { - (yyval.gen) = (yyvsp[(2) - (2)].gen); + (yyval.addr) = (yyvsp[(2) - (2)].addr); } break; case 75: - -/* Line 1806 of yacc.c */ #line 358 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_BRANCH; - (yyval.gen).offset = (yyvsp[(1) - (4)].lval) + pc; + (yyval.addr) = nullgen; + (yyval.addr).type = D_BRANCH; + (yyval.addr).offset = (yyvsp[(1) - (4)].lval) + pc; } break; case 76: - -/* Line 1806 of yacc.c */ #line 364 "a.y" { - (yyval.gen) = nullgen; + (yyval.addr) = nullgen; if(pass == 2) yyerror("undefined label: %s", (yyvsp[(1) - (2)].sym)->name); - (yyval.gen).type = D_BRANCH; - (yyval.gen).sym = (yyvsp[(1) - (2)].sym); - (yyval.gen).offset = (yyvsp[(2) - (2)].lval); + (yyval.addr).type = D_BRANCH; + (yyval.addr).offset = (yyvsp[(2) - (2)].lval); } break; case 77: - -/* Line 1806 of yacc.c */ -#line 373 "a.y" +#line 372 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_BRANCH; - (yyval.gen).sym = (yyvsp[(1) - (2)].sym); - (yyval.gen).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_BRANCH; + (yyval.addr).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval); } break; case 78: - -/* Line 1806 of yacc.c */ -#line 382 "a.y" +#line 380 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = (yyvsp[(1) - (1)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = (yyvsp[(1) - (1)].lval); } break; case 79: - -/* Line 1806 of yacc.c */ -#line 387 "a.y" +#line 385 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = (yyvsp[(1) - (1)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = (yyvsp[(1) - (1)].lval); } break; case 80: - -/* Line 1806 of yacc.c */ -#line 392 "a.y" +#line 390 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = (yyvsp[(1) - (1)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = (yyvsp[(1) - (1)].lval); } break; case 81: - -/* Line 1806 of yacc.c */ -#line 397 "a.y" +#line 395 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = (yyvsp[(1) - (1)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = (yyvsp[(1) - (1)].lval); } break; case 82: - -/* Line 1806 of yacc.c */ -#line 402 "a.y" +#line 400 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_SP; + (yyval.addr) = nullgen; + (yyval.addr).type = D_SP; } break; case 83: - -/* Line 1806 of yacc.c */ -#line 407 "a.y" +#line 405 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = (yyvsp[(1) - (1)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = (yyvsp[(1) - (1)].lval); } break; case 84: - -/* Line 1806 of yacc.c */ -#line 414 "a.y" +#line 412 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_CONST; - (yyval.gen).offset = (yyvsp[(2) - (2)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_CONST; + (yyval.addr).offset = (yyvsp[(2) - (2)].lval); } break; case 85: - -/* Line 1806 of yacc.c */ -#line 420 "a.y" +#line 418 "a.y" { - (yyval.gen) = (yyvsp[(2) - (2)].gen); - (yyval.gen).index = (yyvsp[(2) - (2)].gen).type; - (yyval.gen).type = D_ADDR; + (yyval.addr) = (yyvsp[(2) - (2)].addr); + (yyval.addr).index = (yyvsp[(2) - (2)].addr).type; + (yyval.addr).type = D_ADDR; /* if($2.type == D_AUTO || $2.type == D_PARAM) yyerror("constant cannot be automatic: %s", @@ -2370,76 +2194,62 @@ yyreduce: break; case 86: - -/* Line 1806 of yacc.c */ -#line 431 "a.y" +#line 429 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_SCONST; - memcpy((yyval.gen).sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.gen).sval)); + (yyval.addr) = nullgen; + (yyval.addr).type = D_SCONST; + memcpy((yyval.addr).u.sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.addr).u.sval)); } break; case 87: - -/* Line 1806 of yacc.c */ -#line 437 "a.y" +#line 435 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_FCONST; - (yyval.gen).dval = (yyvsp[(2) - (2)].dval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_FCONST; + (yyval.addr).u.dval = (yyvsp[(2) - (2)].dval); } break; case 88: - -/* Line 1806 of yacc.c */ -#line 443 "a.y" +#line 441 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_FCONST; - (yyval.gen).dval = (yyvsp[(3) - (4)].dval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_FCONST; + (yyval.addr).u.dval = (yyvsp[(3) - (4)].dval); } break; case 89: - -/* Line 1806 of yacc.c */ -#line 449 "a.y" +#line 447 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_FCONST; - (yyval.gen).dval = -(yyvsp[(4) - (5)].dval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_FCONST; + (yyval.addr).u.dval = -(yyvsp[(4) - (5)].dval); } break; case 90: - -/* Line 1806 of yacc.c */ -#line 455 "a.y" +#line 453 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_FCONST; - (yyval.gen).dval = -(yyvsp[(3) - (3)].dval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_FCONST; + (yyval.addr).u.dval = -(yyvsp[(3) - (3)].dval); } break; case 91: - -/* Line 1806 of yacc.c */ -#line 463 "a.y" +#line 461 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_CONST2; - (yyval.gen).offset = (yyvsp[(2) - (2)].con2).v1; - (yyval.gen).offset2 = (yyvsp[(2) - (2)].con2).v2; + (yyval.addr) = nullgen; + (yyval.addr).type = D_CONST2; + (yyval.addr).offset = (yyvsp[(2) - (2)].con2).v1; + (yyval.addr).offset2 = (yyvsp[(2) - (2)].con2).v2; } break; case 92: - -/* Line 1806 of yacc.c */ -#line 472 "a.y" +#line 470 "a.y" { (yyval.con2).v1 = (yyvsp[(1) - (1)].lval); (yyval.con2).v2 = ArgsSizeUnknown; @@ -2447,9 +2257,7 @@ yyreduce: break; case 93: - -/* Line 1806 of yacc.c */ -#line 477 "a.y" +#line 475 "a.y" { (yyval.con2).v1 = -(yyvsp[(2) - (2)].lval); (yyval.con2).v2 = ArgsSizeUnknown; @@ -2457,9 +2265,7 @@ yyreduce: break; case 94: - -/* Line 1806 of yacc.c */ -#line 482 "a.y" +#line 480 "a.y" { (yyval.con2).v1 = (yyvsp[(1) - (3)].lval); (yyval.con2).v2 = (yyvsp[(3) - (3)].lval); @@ -2467,9 +2273,7 @@ yyreduce: break; case 95: - -/* Line 1806 of yacc.c */ -#line 487 "a.y" +#line 485 "a.y" { (yyval.con2).v1 = -(yyvsp[(2) - (4)].lval); (yyval.con2).v2 = (yyvsp[(4) - (4)].lval); @@ -2477,370 +2281,290 @@ yyreduce: break; case 98: - -/* Line 1806 of yacc.c */ -#line 498 "a.y" +#line 496 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_INDIR+D_NONE; - (yyval.gen).offset = (yyvsp[(1) - (1)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_INDIR+D_NONE; + (yyval.addr).offset = (yyvsp[(1) - (1)].lval); } break; case 99: - -/* Line 1806 of yacc.c */ -#line 504 "a.y" +#line 502 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_INDIR+(yyvsp[(3) - (4)].lval); - (yyval.gen).offset = (yyvsp[(1) - (4)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_INDIR+(yyvsp[(3) - (4)].lval); + (yyval.addr).offset = (yyvsp[(1) - (4)].lval); } break; case 100: - -/* Line 1806 of yacc.c */ -#line 510 "a.y" +#line 508 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_INDIR+D_SP; - (yyval.gen).offset = (yyvsp[(1) - (4)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_INDIR+D_SP; + (yyval.addr).offset = (yyvsp[(1) - (4)].lval); } break; case 101: - -/* Line 1806 of yacc.c */ -#line 516 "a.y" +#line 514 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_INDIR+D_NONE; - (yyval.gen).offset = (yyvsp[(1) - (6)].lval); - (yyval.gen).index = (yyvsp[(3) - (6)].lval); - (yyval.gen).scale = (yyvsp[(5) - (6)].lval); - checkscale((yyval.gen).scale); + (yyval.addr) = nullgen; + (yyval.addr).type = D_INDIR+D_NONE; + (yyval.addr).offset = (yyvsp[(1) - (6)].lval); + (yyval.addr).index = (yyvsp[(3) - (6)].lval); + (yyval.addr).scale = (yyvsp[(5) - (6)].lval); + checkscale((yyval.addr).scale); } break; case 102: - -/* Line 1806 of yacc.c */ -#line 525 "a.y" +#line 523 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_INDIR+(yyvsp[(3) - (9)].lval); - (yyval.gen).offset = (yyvsp[(1) - (9)].lval); - (yyval.gen).index = (yyvsp[(6) - (9)].lval); - (yyval.gen).scale = (yyvsp[(8) - (9)].lval); - checkscale((yyval.gen).scale); + (yyval.addr) = nullgen; + (yyval.addr).type = D_INDIR+(yyvsp[(3) - (9)].lval); + (yyval.addr).offset = (yyvsp[(1) - (9)].lval); + (yyval.addr).index = (yyvsp[(6) - (9)].lval); + (yyval.addr).scale = (yyvsp[(8) - (9)].lval); + checkscale((yyval.addr).scale); } break; case 103: - -/* Line 1806 of yacc.c */ -#line 534 "a.y" +#line 532 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_INDIR+(yyvsp[(3) - (9)].lval); - (yyval.gen).offset = (yyvsp[(1) - (9)].lval); - (yyval.gen).index = (yyvsp[(6) - (9)].lval); - (yyval.gen).scale = (yyvsp[(8) - (9)].lval); - checkscale((yyval.gen).scale); + (yyval.addr) = nullgen; + (yyval.addr).type = D_INDIR+(yyvsp[(3) - (9)].lval); + (yyval.addr).offset = (yyvsp[(1) - (9)].lval); + (yyval.addr).index = (yyvsp[(6) - (9)].lval); + (yyval.addr).scale = (yyvsp[(8) - (9)].lval); + checkscale((yyval.addr).scale); } break; case 104: - -/* Line 1806 of yacc.c */ -#line 543 "a.y" +#line 541 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_INDIR+(yyvsp[(2) - (3)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_INDIR+(yyvsp[(2) - (3)].lval); } break; case 105: - -/* Line 1806 of yacc.c */ -#line 548 "a.y" +#line 546 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_INDIR+D_SP; + (yyval.addr) = nullgen; + (yyval.addr).type = D_INDIR+D_SP; } break; case 106: - -/* Line 1806 of yacc.c */ -#line 553 "a.y" +#line 551 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_INDIR+(yyvsp[(3) - (4)].lval); - (yyval.gen).offset = (yyvsp[(1) - (4)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_INDIR+(yyvsp[(3) - (4)].lval); + (yyval.addr).offset = (yyvsp[(1) - (4)].lval); } break; case 107: - -/* Line 1806 of yacc.c */ -#line 559 "a.y" +#line 557 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_INDIR+D_NONE; - (yyval.gen).index = (yyvsp[(2) - (5)].lval); - (yyval.gen).scale = (yyvsp[(4) - (5)].lval); - checkscale((yyval.gen).scale); + (yyval.addr) = nullgen; + (yyval.addr).type = D_INDIR+D_NONE; + (yyval.addr).index = (yyvsp[(2) - (5)].lval); + (yyval.addr).scale = (yyvsp[(4) - (5)].lval); + checkscale((yyval.addr).scale); } break; case 108: - -/* Line 1806 of yacc.c */ -#line 567 "a.y" +#line 565 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_INDIR+(yyvsp[(2) - (8)].lval); - (yyval.gen).index = (yyvsp[(5) - (8)].lval); - (yyval.gen).scale = (yyvsp[(7) - (8)].lval); - checkscale((yyval.gen).scale); + (yyval.addr) = nullgen; + (yyval.addr).type = D_INDIR+(yyvsp[(2) - (8)].lval); + (yyval.addr).index = (yyvsp[(5) - (8)].lval); + (yyval.addr).scale = (yyvsp[(7) - (8)].lval); + checkscale((yyval.addr).scale); } break; case 109: - -/* Line 1806 of yacc.c */ -#line 577 "a.y" +#line 575 "a.y" { - (yyval.gen) = (yyvsp[(1) - (1)].gen); + (yyval.addr) = (yyvsp[(1) - (1)].addr); } break; case 110: - -/* Line 1806 of yacc.c */ -#line 581 "a.y" +#line 579 "a.y" { - (yyval.gen) = (yyvsp[(1) - (6)].gen); - (yyval.gen).index = (yyvsp[(3) - (6)].lval); - (yyval.gen).scale = (yyvsp[(5) - (6)].lval); - checkscale((yyval.gen).scale); + (yyval.addr) = (yyvsp[(1) - (6)].addr); + (yyval.addr).index = (yyvsp[(3) - (6)].lval); + (yyval.addr).scale = (yyvsp[(5) - (6)].lval); + checkscale((yyval.addr).scale); } break; case 111: - -/* Line 1806 of yacc.c */ -#line 590 "a.y" +#line 588 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = (yyvsp[(4) - (5)].lval); - (yyval.gen).sym = (yyvsp[(1) - (5)].sym); - (yyval.gen).offset = (yyvsp[(2) - (5)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = (yyvsp[(4) - (5)].lval); + (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (5)].sym)->name, 0); + (yyval.addr).offset = (yyvsp[(2) - (5)].lval); } break; case 112: - -/* Line 1806 of yacc.c */ -#line 597 "a.y" +#line 595 "a.y" { - (yyval.gen) = nullgen; - (yyval.gen).type = D_STATIC; - (yyval.gen).sym = (yyvsp[(1) - (7)].sym); - (yyval.gen).offset = (yyvsp[(4) - (7)].lval); + (yyval.addr) = nullgen; + (yyval.addr).type = D_STATIC; + (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (7)].sym)->name, 1); + (yyval.addr).offset = (yyvsp[(4) - (7)].lval); } break; case 113: - -/* Line 1806 of yacc.c */ -#line 605 "a.y" +#line 603 "a.y" { (yyval.lval) = 0; } break; case 114: - -/* Line 1806 of yacc.c */ -#line 609 "a.y" +#line 607 "a.y" { (yyval.lval) = (yyvsp[(2) - (2)].lval); } break; case 115: - -/* Line 1806 of yacc.c */ -#line 613 "a.y" +#line 611 "a.y" { (yyval.lval) = -(yyvsp[(2) - (2)].lval); } break; case 117: - -/* Line 1806 of yacc.c */ -#line 620 "a.y" +#line 618 "a.y" { (yyval.lval) = D_AUTO; } break; case 120: - -/* Line 1806 of yacc.c */ -#line 628 "a.y" +#line 626 "a.y" { (yyval.lval) = (yyvsp[(1) - (1)].sym)->value; } break; case 121: - -/* Line 1806 of yacc.c */ -#line 632 "a.y" +#line 630 "a.y" { (yyval.lval) = -(yyvsp[(2) - (2)].lval); } break; case 122: - -/* Line 1806 of yacc.c */ -#line 636 "a.y" +#line 634 "a.y" { (yyval.lval) = (yyvsp[(2) - (2)].lval); } break; case 123: - -/* Line 1806 of yacc.c */ -#line 640 "a.y" +#line 638 "a.y" { (yyval.lval) = ~(yyvsp[(2) - (2)].lval); } break; case 124: - -/* Line 1806 of yacc.c */ -#line 644 "a.y" +#line 642 "a.y" { (yyval.lval) = (yyvsp[(2) - (3)].lval); } break; case 126: - -/* Line 1806 of yacc.c */ -#line 651 "a.y" +#line 649 "a.y" { (yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval); } break; case 127: - -/* Line 1806 of yacc.c */ -#line 655 "a.y" +#line 653 "a.y" { (yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval); } break; case 128: - -/* Line 1806 of yacc.c */ -#line 659 "a.y" +#line 657 "a.y" { (yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval); } break; case 129: - -/* Line 1806 of yacc.c */ -#line 663 "a.y" +#line 661 "a.y" { (yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval); } break; case 130: - -/* Line 1806 of yacc.c */ -#line 667 "a.y" +#line 665 "a.y" { (yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval); } break; case 131: - -/* Line 1806 of yacc.c */ -#line 671 "a.y" +#line 669 "a.y" { (yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval); } break; case 132: - -/* Line 1806 of yacc.c */ -#line 675 "a.y" +#line 673 "a.y" { (yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval); } break; case 133: - -/* Line 1806 of yacc.c */ -#line 679 "a.y" +#line 677 "a.y" { (yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval); } break; case 134: - -/* Line 1806 of yacc.c */ -#line 683 "a.y" +#line 681 "a.y" { (yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval); } break; case 135: - -/* Line 1806 of yacc.c */ -#line 687 "a.y" +#line 685 "a.y" { (yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval); } break; - -/* Line 1806 of yacc.c */ -#line 2831 "y.tab.c" +/* Line 1267 of yacc.c. */ +#line 2566 "y.tab.c" default: break; } - /* User semantic actions sometimes alter yychar, and that requires - that yytoken be updated with the new translation. We take the - approach of translating immediately before every use of yytoken. - One alternative is translating here after every semantic action, - but that translation would be missed if the semantic action invokes - YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or - if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an - incorrect destructor might then be invoked immediately. In the - case of YYERROR or YYBACKUP, subsequent parser actions might lead - to an incorrect destructor call or verbose syntax error message - before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); YYPOPSTACK (yylen); @@ -2849,6 +2573,7 @@ yyreduce: *++yyvsp = yyval; + /* Now `shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ @@ -2868,10 +2593,6 @@ yyreduce: | yyerrlab -- here on detecting error | `------------------------------------*/ yyerrlab: - /* Make sure we have latest lookahead translation. See comments at - user semantic actions for why this is necessary. */ - yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); - /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { @@ -2879,36 +2600,37 @@ yyerrlab: #if ! YYERROR_VERBOSE yyerror (YY_("syntax error")); #else -# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ - yyssp, yytoken) { - char const *yymsgp = YY_("syntax error"); - int yysyntax_error_status; - yysyntax_error_status = YYSYNTAX_ERROR; - if (yysyntax_error_status == 0) - yymsgp = yymsg; - else if (yysyntax_error_status == 1) - { - if (yymsg != yymsgbuf) - YYSTACK_FREE (yymsg); - yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); - if (!yymsg) - { - yymsg = yymsgbuf; - yymsg_alloc = sizeof yymsgbuf; - yysyntax_error_status = 2; - } - else - { - yysyntax_error_status = YYSYNTAX_ERROR; - yymsgp = yymsg; - } - } - yyerror (yymsgp); - if (yysyntax_error_status == 2) - goto yyexhaustedlab; + YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); + if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) + { + YYSIZE_T yyalloc = 2 * yysize; + if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) + yyalloc = YYSTACK_ALLOC_MAXIMUM; + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yyalloc); + if (yymsg) + yymsg_alloc = yyalloc; + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + } + } + + if (0 < yysize && yysize <= yymsg_alloc) + { + (void) yysyntax_error (yymsg, yystate, yychar); + yyerror (yymsg); + } + else + { + yyerror (YY_("syntax error")); + if (yysize != 0) + goto yyexhaustedlab; + } } -# undef YYSYNTAX_ERROR #endif } @@ -2916,7 +2638,7 @@ yyerrlab: if (yyerrstatus == 3) { - /* If just tried and failed to reuse lookahead token after an + /* If just tried and failed to reuse look-ahead token after an error, discard it. */ if (yychar <= YYEOF) @@ -2933,7 +2655,7 @@ yyerrlab: } } - /* Else will try to reuse lookahead token after shifting the error + /* Else will try to reuse look-ahead token after shifting the error token. */ goto yyerrlab1; @@ -2967,7 +2689,7 @@ yyerrlab1: for (;;) { yyn = yypact[yystate]; - if (!yypact_value_is_default (yyn)) + if (yyn != YYPACT_NINF) { yyn += YYTERROR; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) @@ -2990,6 +2712,9 @@ yyerrlab1: YY_STACK_PRINT (yyss, yyssp); } + if (yyn == YYFINAL) + YYACCEPT; + *++yyvsp = yylval; @@ -3014,7 +2739,7 @@ yyabortlab: yyresult = 1; goto yyreturn; -#if !defined(yyoverflow) || YYERROR_VERBOSE +#ifndef yyoverflow /*-------------------------------------------------. | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ @@ -3025,14 +2750,9 @@ yyexhaustedlab: #endif yyreturn: - if (yychar != YYEMPTY) - { - /* Make sure we have latest lookahead translation. See comments at - user semantic actions for why this is necessary. */ - yytoken = YYTRANSLATE (yychar); - yydestruct ("Cleanup: discarding lookahead", - yytoken, &yylval); - } + if (yychar != YYEOF && yychar != YYEMPTY) + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); /* Do not reclaim the symbols of the rule which action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); diff --git a/src/cmd/8a/y.tab.h b/src/cmd/8a/y.tab.h index 14637cb33..d19145548 100644 --- a/src/cmd/8a/y.tab.h +++ b/src/cmd/8a/y.tab.h @@ -1,21 +1,24 @@ -/* A Bison parser, made by GNU Bison 2.5. */ +/* A Bison parser, made by GNU Bison 2.3. */ -/* Bison interface for Yacc-like parsers in C - - Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify +/* Skeleton interface for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - + the Free Software Foundation; either version 2, or (at your option) + any later version. + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License - along with this program. If not, see . */ + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work @@ -26,11 +29,10 @@ special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. - + This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ - /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE @@ -112,11 +114,8 @@ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE -{ - -/* Line 2068 of yacc.c */ #line 38 "a.y" - +{ Sym *sym; int32 lval; struct { @@ -125,19 +124,16 @@ typedef union YYSTYPE } con2; double dval; char sval[8]; - Gen gen; - Gen2 gen2; - - - -/* Line 2068 of yacc.c */ -#line 135 "y.tab.h" -} YYSTYPE; -# define YYSTYPE_IS_TRIVIAL 1 + Addr addr; + Addr2 addr2; +} +/* Line 1529 of yacc.c. */ +#line 132 "y.tab.h" + YYSTYPE; # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 #endif extern YYSTYPE yylval; - diff --git a/src/cmd/8c/gc.h b/src/cmd/8c/gc.h index b668b4c63..87b8e22bc 100644 --- a/src/cmd/8c/gc.h +++ b/src/cmd/8c/gc.h @@ -46,11 +46,8 @@ #define SZ_DOUBLE 8 #define FNX 100 -typedef struct Adr Adr; -typedef struct Prog Prog; typedef struct Case Case; typedef struct C1 C1; -typedef struct Var Var; typedef struct Reg Reg; typedef struct Rgn Rgn; typedef struct Renv Renv; @@ -64,30 +61,10 @@ EXTERN struct short ptr; } idx; -struct Adr -{ - int32 offset; - int32 offset2; - double dval; - char sval[NSNAME]; - - Sym* sym; - uchar type; - uchar index; - uchar etype; - uchar scale; /* doubles as width in DATA op */ -}; -#define A ((Adr*)0) +#define A ((Addr*)0) #define INDEXED 9 -struct Prog -{ - Adr from; - Adr to; - Prog* link; - int32 lineno; - short as; -}; + #define P ((Prog*)0) struct Case @@ -106,14 +83,6 @@ struct C1 int32 label; }; -struct Var -{ - int32 offset; - Sym* sym; - char name; - char etype; -}; - struct Reg { int32 pc; @@ -171,7 +140,6 @@ EXTERN Node fconstnode; EXTERN int32 continpc; EXTERN int32 curarg; EXTERN int32 cursafe; -EXTERN Prog* firstp; EXTERN Prog* lastp; EXTERN int32 maxargsafe; EXTERN int mnstring; @@ -226,7 +194,6 @@ EXTERN Reg* firstr; EXTERN Reg* lastr; EXTERN Reg zreg; EXTERN Reg* freer; -EXTERN Var var[NVAR]; EXTERN int32* idom; EXTERN Reg** rpo2r; EXTERN int32 maxnr; @@ -287,7 +254,7 @@ void regaalloc1(Node*, Node*); void regaalloc(Node*, Node*); void regind(Node*, Node*); void gprep(Node*, Node*); -void naddr(Node*, Adr*); +void naddr(Node*, Addr*); void gmove(Node*, Node*); void gins(int a, Node*, Node*); void fgopcode(int, Node*, Node*, int, int); @@ -315,19 +282,11 @@ void nullwarn(Node*, Node*); void sextern(Sym*, Node*, int32, int32); void gextern(Sym*, Node*, int32, int32); void outcode(void); -void ieeedtod(Ieee*, double); /* * list */ void listinit(void); -int Pconv(Fmt*); -int Aconv(Fmt*); -int Dconv(Fmt*); -int Sconv(Fmt*); -int Rconv(Fmt*); -int Xconv(Fmt*); -int Bconv(Fmt*); /* * reg.c @@ -336,7 +295,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*, Addr*); void prop(Reg*, Bits, Bits); void loopit(Reg*, int32); void synch(Reg*, Bits); @@ -344,7 +303,7 @@ uint32 allreg(uint32, Rgn*); void paint1(Reg*, int); uint32 paint2(Reg*, int); void paint3(Reg*, int, int32, int); -void addreg(Adr*, int); +void addreg(Addr*, int); /* * peep.c @@ -353,17 +312,17 @@ void peep(void); void excise(Reg*); Reg* uniqp(Reg*); Reg* uniqs(Reg*); -int regtyp(Adr*); -int anyvar(Adr*); +int regtyp(Addr*); +int anyvar(Addr*); int subprop(Reg*); int copyprop(Reg*); -int copy1(Adr*, Adr*, Reg*, int); -int copyu(Prog*, Adr*, Adr*); +int copy1(Addr*, Addr*, Reg*, int); +int copyu(Prog*, Addr*, Addr*); -int copyas(Adr*, Adr*); -int copyau(Adr*, Adr*); -int copysub(Adr*, Adr*, Adr*, int); -int copysub1(Prog*, Adr*, Adr*, int); +int copyas(Addr*, Addr*); +int copyau(Addr*, Addr*); +int copysub(Addr*, Addr*, Addr*, int); +int copysub1(Prog*, Addr*, Addr*, int); int32 RtoB(int); int32 FtoB(int); @@ -401,14 +360,6 @@ void mulgen(Type*, Node*, Node*); void genmuladd(Node*, Node*, int, Node*); void shiftit(Type*, Node*, Node*); -#pragma varargck type "A" int -#pragma varargck type "B" Bits -#pragma varargck type "D" Adr* -#pragma varargck type "lD" Adr* -#pragma varargck type "P" Prog* -#pragma varargck type "R" int -#pragma varargck type "S" char* - /* wrecklessly steal a field */ #define rplink label diff --git a/src/cmd/8c/list.c b/src/cmd/8c/list.c index 8506e08ef..1730eccd0 100644 --- a/src/cmd/8c/list.c +++ b/src/cmd/8c/list.c @@ -34,319 +34,5 @@ void listinit(void) { - - fmtinstall('A', Aconv); - fmtinstall('B', Bconv); - fmtinstall('P', Pconv); - fmtinstall('S', Sconv); - fmtinstall('D', Dconv); - fmtinstall('R', Rconv); -} - -int -Bconv(Fmt *fp) -{ - char str[STRINGSZ], ss[STRINGSZ], *s; - Bits bits; - int i; - - str[0] = 0; - bits = va_arg(fp->args, Bits); - while(bany(&bits)) { - i = bnum(bits); - if(str[0]) - strcat(str, " "); - if(var[i].sym == S) { - sprint(ss, "$%d", var[i].offset); - s = ss; - } else - s = var[i].sym->name; - if(strlen(str) + strlen(s) + 1 >= STRINGSZ) - break; - strcat(str, s); - bits.b[i/32] &= ~(1L << (i%32)); - } - return fmtstrcpy(fp, str); -} - -int -Pconv(Fmt *fp) -{ - char str[STRINGSZ]; - Prog *p; - - p = va_arg(fp->args, Prog*); - 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,%D", - p->lineno, p->as, &p->from, &p->to); - break; - } - return fmtstrcpy(fp, str); -} - -int -Aconv(Fmt *fp) -{ - int i; - - i = va_arg(fp->args, int); - return fmtstrcpy(fp, anames[i]); -} - -int -Dconv(Fmt *fp) -{ - char str[STRINGSZ], s[STRINGSZ]; - Adr *a; - int i; - - a = va_arg(fp->args, Adr*); - i = a->type; - - if(fp->flags & FmtLong) { - if(i == D_CONST2) - sprint(str, "$%d-%d", a->offset, a->offset2); - else { - // ATEXT dst is not constant - sprint(str, "!!%D", a); - } - goto brk; - } - - if(i >= D_INDIR) { - if(a->offset) - sprint(str, "%d(%R)", a->offset, i-D_INDIR); - else - sprint(str, "(%R)", i-D_INDIR); - goto brk; - } - switch(i) { - default: - if(a->offset) - sprint(str, "$%d,%R", a->offset, i); - else - sprint(str, "%R", i); - break; - - case D_NONE: - str[0] = 0; - break; - - case D_BRANCH: - sprint(str, "%d", a->offset); - break; - - case D_EXTERN: - sprint(str, "%s+%d(SB)", a->sym->name, a->offset); - break; - - case D_STATIC: - sprint(str, "%s<>+%d(SB)", a->sym->name, a->offset); - break; - - case D_AUTO: - if(a->sym) - sprint(str, "%s+%d(SP)", a->sym->name, a->offset); - else - sprint(str, "%d(SP)", a->offset); - break; - - case D_PARAM: - if(a->sym) - sprint(str, "%s+%d(FP)", a->sym->name, a->offset); - else - sprint(str, "%d(FP)", a->offset); - break; - - case D_CONST: - sprint(str, "$%d", a->offset); - break; - - case D_CONST2: - if(!(fp->flags & FmtLong)) { - // D_CONST2 outside of ATEXT should not happen - sprint(str, "!!$%d-%d", a->offset, a->offset2); - } - break; - - case D_FCONST: - sprint(str, "$(%.17e)", a->dval); - break; - - case D_SCONST: - sprint(str, "$\"%S\"", a->sval); - break; - - case D_ADDR: - a->type = a->index; - a->index = D_NONE; - sprint(str, "$%D", a); - a->index = a->type; - a->type = D_ADDR; - goto conv; - } -brk: - if(a->index != D_NONE) { - sprint(s, "(%R*%d)", (int)a->index, (int)a->scale); - strcat(str, s); - } -conv: - return fmtstrcpy(fp, str); -} - -char* regstr[] = -{ - "AL", /* [D_AL] */ - "CL", - "DL", - "BL", - "AH", - "CH", - "DH", - "BH", - - "AX", /* [D_AX] */ - "CX", - "DX", - "BX", - "SP", - "BP", - "SI", - "DI", - - "F0", /* [D_F0] */ - "F1", - "F2", - "F3", - "F4", - "F5", - "F6", - "F7", - - "CS", /* [D_CS] */ - "SS", - "DS", - "ES", - "FS", - "GS", - - "GDTR", /* [D_GDTR] */ - "IDTR", /* [D_IDTR] */ - "LDTR", /* [D_LDTR] */ - "MSW", /* [D_MSW] */ - "TASK", /* [D_TASK] */ - - "CR0", /* [D_CR] */ - "CR1", - "CR2", - "CR3", - "CR4", - "CR5", - "CR6", - "CR7", - - "DR0", /* [D_DR] */ - "DR1", - "DR2", - "DR3", - "DR4", - "DR5", - "DR6", - "DR7", - - "TR0", /* [D_TR] */ - "TR1", - "TR2", - "TR3", - "TR4", - "TR5", - "TR6", - "TR7", - - "X0", /* [D_X0] */ - "X1", - "X2", - "X3", - "X4", - "X5", - "X6", - "X7", - - "NONE", /* [D_NONE] */ -}; - -int -Rconv(Fmt *fp) -{ - char str[STRINGSZ]; - int r; - - r = va_arg(fp->args, int); - if(r >= D_AL && r <= D_NONE) - sprint(str, "%s", regstr[r-D_AL]); - else - sprint(str, "gok(%d)", r); - - return fmtstrcpy(fp, str); -} - -int -Sconv(Fmt *fp) -{ - int i, c; - char str[STRINGSZ], *p, *a; - - a = va_arg(fp->args, char*); - p = str; - for(i=0; i= 'a' && c <= 'z' || - c >= 'A' && c <= 'Z' || - c >= '0' && c <= '9') { - *p++ = c; - continue; - } - *p++ = '\\'; - switch(c) { - default: - if(c < 040 || c >= 0177) - break; /* not portable */ - p[-1] = c; - continue; - case 0: - *p++ = 'z'; - continue; - case '\\': - case '"': - *p++ = c; - continue; - case '\n': - *p++ = 'n'; - continue; - case '\t': - *p++ = 't'; - continue; - } - *p++ = (c>>6) + '0'; - *p++ = ((c>>3) & 7) + '0'; - *p++ = (c & 7) + '0'; - } - *p = 0; - return fmtstrcpy(fp, str); + listinit8(); } diff --git a/src/cmd/8c/peep.c b/src/cmd/8c/peep.c index da0127d11..4f58fc05c 100644 --- a/src/cmd/8c/peep.c +++ b/src/cmd/8c/peep.c @@ -217,7 +217,7 @@ uniqs(Reg *r) } int -regtyp(Adr *a) +regtyp(Addr *a) { int t; @@ -245,7 +245,7 @@ int subprop(Reg *r0) { Prog *p; - Adr *v1, *v2; + Addr *v1, *v2; Reg *r; int t; @@ -365,7 +365,7 @@ int copyprop(Reg *r0) { Prog *p; - Adr *v1, *v2; + Addr *v1, *v2; Reg *r; p = r0->prog; @@ -379,7 +379,7 @@ copyprop(Reg *r0) } int -copy1(Adr *v1, Adr *v2, Reg *r, int f) +copy1(Addr *v1, Addr *v2, Reg *r, int f) { int t; Prog *p; @@ -464,7 +464,7 @@ copy1(Adr *v1, Adr *v2, Reg *r, int f) * 0 otherwise (not touched) */ int -copyu(Prog *p, Adr *v, Adr *s) +copyu(Prog *p, Addr *v, Addr *s) { switch(p->as) { @@ -740,7 +740,7 @@ copyu(Prog *p, Adr *v, Adr *s) * semantics */ int -copyas(Adr *a, Adr *v) +copyas(Addr *a, Addr *v) { if(a->type != v->type) return 0; @@ -756,7 +756,7 @@ copyas(Adr *a, Adr *v) * either direct or indirect */ int -copyau(Adr *a, Adr *v) +copyau(Addr *a, Addr *v) { if(copyas(a, v)) @@ -775,7 +775,7 @@ copyau(Adr *a, Adr *v) * return failure to substitute */ int -copysub(Adr *a, Adr *v, Adr *s, int f) +copysub(Addr *a, Addr *v, Addr *s, int f) { int t; diff --git a/src/cmd/8c/reg.c b/src/cmd/8c/reg.c index a3d5d6115..e6ba8bcb3 100644 --- a/src/cmd/8c/reg.c +++ b/src/cmd/8c/reg.c @@ -558,7 +558,7 @@ brk: if(debug['R'] && debug['v']) { print("after pass 7 (peep)\n"); for(r=firstr; r; r=r->link) - print("%04d %P\n", r->pc, r->prog); + print("%04d %P\n", (int)r->pc, r->prog); print("\n"); } @@ -602,8 +602,10 @@ brk: r1 = 0; /* set */ for(r = firstr; r != R; r = r->link) { p = r->prog; - if(p->to.type == D_BRANCH) + if(p->to.type == D_BRANCH) { p->to.offset = r->s2->pc; + p->to.u.branch = r->s2->prog; + } r1 = r; } @@ -638,7 +640,7 @@ void addmove(Reg *r, int bn, int rn, int f) { Prog *p, *p1; - Adr *a; + Addr *a; Var *v; p1 = alloc(sizeof(*p1)); @@ -697,13 +699,13 @@ doregbits(int r) } Bits -mkvar(Reg *r, Adr *a) +mkvar(Reg *r, Addr *a) { Var *v; int i, t, n, et, z; int32 o; Bits bit; - Sym *s; + LSym *s; /* * mark registers used @@ -730,7 +732,7 @@ mkvar(Reg *r, Adr *a) break; } s = a->sym; - if(s == S) + if(s == nil) goto none; if(s->name[0] == '.') goto none; @@ -1121,7 +1123,7 @@ uint32 regset(Reg *r, uint32 bb) { uint32 b, set; - Adr v; + Addr v; int c; set = 0; @@ -1140,7 +1142,7 @@ uint32 reguse(Reg *r, uint32 bb) { uint32 b, set; - Adr v; + Addr v; int c; set = 0; @@ -1287,7 +1289,7 @@ paint3(Reg *r, int bn, int32 rb, int rn) } void -addreg(Adr *a, int rn) +addreg(Addr *a, int rn) { a->sym = 0; @@ -1373,10 +1375,11 @@ fixjmp(Reg *firstr) for(r=firstr; r; r=r->link) { p = r->prog; if(debug['R'] && debug['v']) - print("%04d %P\n", r->pc, p); + print("%04d %P\n", (int)r->pc, p); if(p->as != ACALL && p->to.type == D_BRANCH && r->s2 && r->s2->prog->as == AJMP) { r->s2 = chasejmp(r->s2, &jmploop); p->to.offset = r->s2->pc; + p->to.u.branch = r->s2->prog; if(debug['R'] && debug['v']) print("->%P\n", p); } @@ -1397,7 +1400,7 @@ fixjmp(Reg *firstr) // Let it stay. } else { if(debug['R'] && debug['v']) - print("del %04d %P\n", r->pc, p); + print("del %04d %P\n", (int)r->pc, p); p->as = ANOP; } } @@ -1410,7 +1413,7 @@ fixjmp(Reg *firstr) p = r->prog; if(p->as == AJMP && p->to.type == D_BRANCH && r->s2 == r->link) { if(debug['R'] && debug['v']) - print("del %04d %P\n", r->pc, p); + print("del %04d %P\n", (int)r->pc, p); p->as = ANOP; } } @@ -1431,7 +1434,7 @@ fixjmp(Reg *firstr) if(debug['R'] && debug['v']) { print("\n"); for(r=firstr; r; r=r->link) - print("%04d %P\n", r->pc, r->prog); + print("%04d %P\n", (int)r->pc, r->prog); print("\n"); } } diff --git a/src/cmd/8c/swt.c b/src/cmd/8c/swt.c index b68197447..ae36f84ea 100644 --- a/src/cmd/8c/swt.c +++ b/src/cmd/8c/swt.c @@ -169,7 +169,7 @@ outstring(char *s, int32 n) p->from.offset += nstring - NSNAME; p->from.scale = NSNAME; p->to.type = D_SCONST; - memmove(p->to.sval, string, NSNAME); + memmove(p->to.u.sval, string, NSNAME); mnstring = 0; } n--; @@ -190,7 +190,7 @@ sextern(Sym *s, Node *a, int32 o, int32 w) p->from.offset += o+e; p->from.scale = lw; p->to.type = D_SCONST; - memmove(p->to.sval, a->cstring+e, lw); + memmove(p->to.u.sval, a->cstring+e, lw); } } @@ -220,29 +220,12 @@ gextern(Sym *s, Node *a, int32 o, int32 w) } } -void zname(Biobuf*, Sym*, int); -void zaddr(Biobuf*, Adr*, int); -void outhist(Biobuf*); - void outcode(void) { - struct { Sym *sym; short type; } h[NSYM]; - Prog *p; - Sym *s; - int f, sf, st, t, sym; + int f; Biobuf b; - if(debug['S']) { - for(p = firstp; p != P; p = p->link) - if(p->as != ADATA && p->as != AGLOBL) - pc--; - for(p = firstp; p != P; p = p->link) { - print("%P\n", p); - if(p->as != ADATA && p->as != AGLOBL) - pc++; - } - } f = open(outfile, OWRITE); if(f < 0) { diag(Z, "cannot open %s", outfile); @@ -250,7 +233,7 @@ outcode(void) } Binit(&b, f, OWRITE); - Bprint(&b, "go object %s %s %s\n", getgoos(), thestring, getgoversion()); + Bprint(&b, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion()); if(pragcgobuf.to > pragcgobuf.start) { Bprint(&b, "\n"); Bprint(&b, "$$ // exports\n\n"); @@ -261,258 +244,12 @@ outcode(void) } Bprint(&b, "!\n"); - outhist(&b); - for(sym=0; symlink) { - jackpot: - sf = 0; - s = p->from.sym; - while(s != S) { - sf = s->sym; - if(sf < 0 || sf >= NSYM) - sf = 0; - t = p->from.type; - if(t == D_ADDR) - t = p->from.index; - if(h[sf].type == t) - if(h[sf].sym == s) - break; - s->sym = sym; - zname(&b, s, t); - h[sym].sym = s; - h[sym].type = t; - sf = sym; - sym++; - if(sym >= NSYM) - sym = 1; - break; - } - st = 0; - s = p->to.sym; - while(s != S) { - st = s->sym; - if(st < 0 || st >= NSYM) - st = 0; - t = p->to.type; - if(t == D_ADDR) - t = p->to.index; - if(h[st].type == t) - if(h[st].sym == s) - break; - s->sym = sym; - zname(&b, s, t); - h[sym].sym = s; - h[sym].type = t; - st = sym; - sym++; - if(sym >= NSYM) - sym = 1; - if(st == sf) - goto jackpot; - break; - } - BPUTLE2(&b, p->as); - BPUTLE4(&b, p->lineno); - zaddr(&b, &p->from, sf); - zaddr(&b, &p->to, st); - } + writeobj(ctxt, &b); Bterm(&b); close(f); - firstp = P; lastp = P; } -void -outhist(Biobuf *b) -{ - Hist *h; - char *p, *q, *op, c; - Prog pg; - int n; - char *tofree; - static int first = 1; - static char *goroot, *goroot_final; - - if(first) { - // Decide whether we need to rewrite paths from $GOROOT to $GOROOT_FINAL. - first = 0; - goroot = getenv("GOROOT"); - goroot_final = getenv("GOROOT_FINAL"); - if(goroot == nil) - goroot = ""; - if(goroot_final == nil) - goroot_final = goroot; - if(strcmp(goroot, goroot_final) == 0) { - goroot = nil; - goroot_final = nil; - } - } - - tofree = nil; - pg = zprog; - pg.as = AHISTORY; - c = pathchar(); - for(h = hist; h != H; h = h->link) { - p = h->name; - if(p != nil && goroot != nil) { - n = strlen(goroot); - if(strncmp(p, goroot, strlen(goroot)) == 0 && p[n] == '/') { - tofree = smprint("%s%s", goroot_final, p+n); - p = tofree; - } - } - op = 0; - if(systemtype(Windows) && p && p[1] == ':'){ - c = p[2]; - } else if(p && p[0] != c && h->offset == 0 && pathname){ - if(systemtype(Windows) && pathname[1] == ':') { - op = p; - p = pathname; - c = p[2]; - } else if(pathname[0] == c){ - op = p; - p = pathname; - } - } - while(p) { - q = utfrune(p, c); - if(q) { - n = q-p; - if(n == 0){ - n = 1; /* leading "/" */ - *p = '/'; /* don't emit "\" on windows */ - } - q++; - } else { - n = strlen(p); - q = 0; - } - if(n) { - BPUTLE2(b, ANAME); - BPUTC(b, D_FILE); - BPUTC(b, 1); - BPUTC(b, '<'); - Bwrite(b, p, n); - BPUTC(b, 0); - } - p = q; - if(p == 0 && op) { - p = op; - op = 0; - } - } - pg.lineno = h->line; - pg.to.type = zprog.to.type; - pg.to.offset = h->offset; - if(h->offset) - pg.to.type = D_CONST; - - BPUTLE2(b, pg.as); - BPUTLE4(b, pg.lineno); - zaddr(b, &pg.from, 0); - zaddr(b, &pg.to, 0); - - if(tofree) { - free(tofree); - tofree = nil; - } - } -} - -void -zname(Biobuf *b, Sym *s, int t) -{ - char *n; - uint32 sig; - - if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){ - sig = sign(s); - BPUTLE2(b, ASIGNAME); - BPUTLE4(b, sig); - s->sig = SIGDONE; - } - else{ - BPUTLE2(b, ANAME); /* as */ - } - BPUTC(b, t); /* type */ - BPUTC(b, s->sym); /* sym */ - n = s->name; - while(*n) { - BPUTC(b, *n); - n++; - } - BPUTC(b, 0); -} - -void -zaddr(Biobuf *b, Adr *a, int s) -{ - int32 l; - int i, t; - char *n; - Ieee e; - - t = 0; - if(a->index != D_NONE || a->scale != 0) - t |= T_INDEX; - if(s != 0) - t |= T_SYM; - - switch(a->type) { - default: - t |= T_TYPE; - case D_NONE: - if(a->offset != 0) - t |= T_OFFSET; - break; - case D_FCONST: - t |= T_FCONST; - break; - case D_SCONST: - t |= T_SCONST; - break; - case D_CONST2: - t |= T_OFFSET|T_OFFSET2; - break; - } - BPUTC(b, t); - - if(t & T_INDEX) { /* implies index, scale */ - BPUTC(b, a->index); - BPUTC(b, a->scale); - } - if(t & T_OFFSET) { /* implies offset */ - l = a->offset; - BPUTLE4(b, l); - } - if(t & T_OFFSET2) { /* implies offset2 */ - l = a->offset2; - BPUTLE4(b, l); - } - if(t & T_SYM) /* implies sym */ - BPUTC(b, s); - if(t & T_FCONST) { - ieeedtod(&e, a->dval); - BPUTLE4(b, e.l); - BPUTLE4(b, e.h); - return; - } - if(t & T_SCONST) { - n = a->sval; - for(i=0; itype); -} - int32 align(int32 i, Type *t, int op, int32 *maxalign) { diff --git a/src/cmd/8c/txt.c b/src/cmd/8c/txt.c index 5c486af38..25082de05 100644 --- a/src/cmd/8c/txt.c +++ b/src/cmd/8c/txt.c @@ -30,14 +30,23 @@ #include "gc.h" + +int thechar = '8'; +char *thestring = "386"; + +LinkArch *thelinkarch = &link386; + +void +linkarchinit(void) +{ +} + void ginit(void) { int i; Type *t; - thechar = '8'; - thestring = "386"; exregoffset = 0; exfregoffset = 0; listinit(); @@ -48,7 +57,6 @@ ginit(void) breakpc = -1; continpc = -1; cases = C; - firstp = P; lastp = P; tfield = types[TLONG]; @@ -156,17 +164,18 @@ gclean(void) void nextpc(void) { + Plist *pl; p = alloc(sizeof(*p)); *p = zprog; p->lineno = nearln; + p->pc = pc; pc++; - if(firstp == P) { - firstp = p; - lastp = p; - return; - } - lastp->link = p; + if(lastp == nil) { + pl = linknewplist(ctxt); + pl->firstpc = p; + } else + lastp->link = p; lastp = p; } @@ -188,7 +197,8 @@ gargs(Node *n, Node *tn1, Node *tn2) cursafe = regs; } -int nareg(void) +int +nareg(void) { int i, n; @@ -435,7 +445,7 @@ regind(Node *n, Node *nn) } void -naddr(Node *n, Adr *a) +naddr(Node *n, Addr *a) { int32 v; @@ -450,11 +460,11 @@ naddr(Node *n, Adr *a) case OREGISTER: a->type = n->reg; - a->sym = S; + a->sym = nil; break; case OEXREG: - a->type = D_INDIR + D_GS; + a->type = D_INDIR + D_TLS; a->offset = n->reg - 1; break; @@ -495,14 +505,14 @@ naddr(Node *n, Adr *a) case OINDREG: a->type = n->reg+D_INDIR; - a->sym = S; + a->sym = nil; a->offset = n->xoffset; break; case ONAME: a->etype = n->etype; a->type = D_STATIC; - a->sym = n->sym; + a->sym = linksym(n->sym); a->offset = n->xoffset; if(n->class == CSTATIC) break; @@ -523,10 +533,10 @@ naddr(Node *n, Adr *a) case OCONST: if(typefd[n->type->etype]) { a->type = D_FCONST; - a->dval = n->fconst; + a->u.dval = n->fconst; break; } - a->sym = S; + a->sym = nil; a->type = D_CONST; a->offset = n->vconst; break; @@ -1366,9 +1376,10 @@ gbranch(int o) void patch(Prog *op, int32 pc) { - op->to.offset = pc; op->to.type = D_BRANCH; + op->to.u.branch = nil; + op->pcond = nil; } void @@ -1378,7 +1389,7 @@ gpseudo(int a, Sym *s, Node *n) nextpc(); p->as = a; p->from.type = D_EXTERN; - p->from.sym = s; + p->from.sym = linksym(s); switch(a) { case ATEXT: diff --git a/src/cmd/8g/cgen.c b/src/cmd/8g/cgen.c index cc28a3145..d626c2eb0 100644 --- a/src/cmd/8g/cgen.c +++ b/src/cmd/8g/cgen.c @@ -242,6 +242,7 @@ cgen(Node *n, Node *res) case OOR: case OXOR: case OADD: + case OADDPTR: case OMUL: a = optoas(n->op, nl->type); if(a == AIMULB) { @@ -522,6 +523,7 @@ agen(Node *n, Node *res) // The generated code is just going to panic, so it need not // be terribly efficient. See issue 3670. tempname(&n1, n->type); + gvardef(&n1); clearfat(&n1); regalloc(&n2, types[tptr], res); gins(ALEAL, &n1, &n2); @@ -934,6 +936,13 @@ bgen(Node *n, int true, int likely, Prog *to) patch(gins(AEND, N, N), to); return; } + + while(n->op == OCONVNOP) { + n = n->left; + if(n->ninit != nil) + genlist(n->ninit); + } + nl = n->left; nr = N; @@ -1203,6 +1212,8 @@ sgen(Node *n, Node *res, int64 w) { Node dst, src, tdst, tsrc; int32 c, q, odst, osrc; + NodeList *l; + Prog *p; if(debug['g']) { print("\nsgen w=%lld\n", w); @@ -1223,6 +1234,13 @@ sgen(Node *n, Node *res, int64 w) return; } + // If copying .args, that's all the results, so record definition sites + // for them for the liveness analysis. + if(res->op == ONAME && strcmp(res->sym->name, ".args") == 0) + for(l = curfn->dcl; l != nil; l = l->next) + if(l->n->class == PPARAMOUT) + gvardef(l->n); + // Avoid taking the address for simple enough types. if(componentgen(n, res)) return; @@ -1255,6 +1273,10 @@ sgen(Node *n, Node *res, int64 w) agen(n, &src); else gmove(&tsrc, &src); + + if(res->op == ONAME) + gvardef(res); + if(res->addable) agen(res, &dst); else @@ -1294,10 +1316,16 @@ sgen(Node *n, Node *res, int64 w) } else { gins(ACLD, N, N); // paranoia. TODO(rsc): remove? // normal direction - if(q >= 4) { + if(q > 128 || (q >= 4 && nacl)) { gconreg(AMOVL, q, D_CX); gins(AREP, N, N); // repeat gins(AMOVSL, N, N); // MOVL *(SI)+,*(DI)+ + } else if(q >= 4) { + p = gins(ADUFFCOPY, N, N); + p->to.type = D_ADDR; + p->to.sym = linksym(pkglookup("duffcopy", runtimepkg)); + // 10 and 128 = magic constants: see ../../pkg/runtime/asm_386.s + p->to.offset = 10*(128-q); } else while(q > 0) { gins(AMOVSL, N, N); // MOVL *(SI)+,*(DI)+ @@ -1369,8 +1397,17 @@ componentgen(Node *nr, Node *nl) } } + // nl and nr are 'cadable' which basically means they are names (variables) now. + // If they are the same variable, don't generate any code, because the + // VARDEF we generate will mark the old value as dead incorrectly. + // (And also the assignments are useless.) + if(nr != N && nl->op == ONAME && nr->op == ONAME && nl == nr) + goto yes; + switch(nl->type->etype) { case TARRAY: + if(nl->op == ONAME) + gvardef(nl); nodl.xoffset += Array_array; nodl.type = ptrto(nl->type->type); @@ -1404,6 +1441,8 @@ componentgen(Node *nr, Node *nl) goto yes; case TSTRING: + if(nl->op == ONAME) + gvardef(nl); nodl.xoffset += Array_array; nodl.type = ptrto(types[TUINT8]); @@ -1427,6 +1466,8 @@ componentgen(Node *nr, Node *nl) goto yes; case TINTER: + if(nl->op == ONAME) + gvardef(nl); nodl.xoffset += Array_array; nodl.type = ptrto(types[TUINT8]); diff --git a/src/cmd/8g/galign.c b/src/cmd/8g/galign.c index 2c8aaa0a4..fbd2e9ad3 100644 --- a/src/cmd/8g/galign.c +++ b/src/cmd/8g/galign.c @@ -8,6 +8,12 @@ int thechar = '8'; char* thestring = "386"; +LinkArch* thelinkarch = &link386; + +void +linkarchinit(void) +{ +} vlong MAXWIDTH = (1LL<<32) - 1; @@ -28,6 +34,7 @@ betypeinit(void) { widthptr = 4; widthint = 4; + widthreg = 4; zprog.link = P; zprog.as = AGOK; @@ -36,5 +43,5 @@ betypeinit(void) zprog.from.scale = 0; zprog.to = zprog.from; - listinit(); + listinit8(); } diff --git a/src/cmd/8g/gg.h b/src/cmd/8g/gg.h index 55fdded0b..bdefa93b5 100644 --- a/src/cmd/8g/gg.h +++ b/src/cmd/8g/gg.h @@ -9,42 +9,6 @@ #include "../gc/go.h" #include "../8l/8.out.h" -typedef struct Addr Addr; - -struct Addr -{ - int32 offset; - int32 offset2; - - union { - double dval; - vlong vval; - Prog* branch; - char sval[NSNAME]; - } u; - - Sym* gotype; - Sym* sym; - Node* node; - int width; - uchar type; - uchar index; - uchar etype; - uchar scale; /* doubles as width in DATA op */ -}; -#define A ((Addr*)0) - -struct Prog -{ - 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 - Prog* link; // next instruction in this func - void* opt; // for optimizer passes -}; - #define TEXTFLAG from.scale // foptoas flags @@ -59,15 +23,14 @@ EXTERN int32 dynloc; EXTERN uchar reg[D_NONE]; EXTERN int32 pcloc; // instruction counter EXTERN Strlit emptystring; -extern char* anames[]; EXTERN Prog zprog; EXTERN Node* newproc; EXTERN Node* deferproc; EXTERN Node* deferreturn; EXTERN Node* panicindex; EXTERN Node* panicslice; +EXTERN Node* panicdiv; EXTERN Node* throwreturn; -EXTERN int maxstksize; extern uint32 unmappedzero; @@ -168,14 +131,6 @@ void datagostring(Strlit*, Addr*); /* * list.c */ -int Aconv(Fmt*); -int Dconv(Fmt*); -int Pconv(Fmt*); -int Rconv(Fmt*); -int Yconv(Fmt*); void listinit(void); void zaddr(Biobuf*, Addr*, int, int); - -#pragma varargck type "D" Addr* -#pragma varargck type "lD" Addr* diff --git a/src/cmd/8g/ggen.c b/src/cmd/8g/ggen.c index fa5ed00dd..2285a04e6 100644 --- a/src/cmd/8g/ggen.c +++ b/src/cmd/8g/ggen.c @@ -9,61 +9,100 @@ #include "gg.h" #include "opt.h" -static Prog* appendp(Prog*, int, int, int32, int, int32); +static Prog *appendpp(Prog*, int, int, vlong, int, vlong); +static Prog *zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *ax); void -defframe(Prog *ptxt, Bvec *bv) +defframe(Prog *ptxt) { - uint32 frame; + uint32 frame, ax; Prog *p; - int i, j; + vlong lo, hi; + NodeList *l; + Node *n; // fill in argument size ptxt->to.offset2 = rnd(curfn->type->argwid, widthptr); // fill in final stack size - if(stksize > maxstksize) - maxstksize = stksize; - frame = rnd(maxstksize+maxarg, widthptr); + frame = rnd(stksize+maxarg, widthptr); ptxt->to.offset = frame; - maxstksize = 0; - - // insert code to clear pointered part of the frame, - // so that garbage collector only sees initialized values + + // insert code to zero ambiguously live variables + // so that the garbage collector only sees initialized values // when it looks for pointers. p = ptxt; - if(stkzerosize >= 8*widthptr) { - p = appendp(p, AMOVL, D_CONST, 0, D_AX, 0); - p = appendp(p, AMOVL, D_CONST, stkzerosize/widthptr, D_CX, 0); - p = appendp(p, ALEAL, D_SP+D_INDIR, frame-stkzerosize, D_DI, 0); - p = appendp(p, AREP, D_NONE, 0, D_NONE, 0); - appendp(p, ASTOSL, D_NONE, 0, D_NONE, 0); - } else { - j = (stkptrsize - stkzerosize)/widthptr * 2; - for(i=0; idcl; l != nil; l = l->next) { + n = l->n; + if(!n->needzero) + continue; + if(n->class != PAUTO) + fatal("needzero class %d", n->class); + if(n->type->width % widthptr != 0 || n->xoffset % widthptr != 0 || n->type->width == 0) + fatal("var %lN has size %d offset %d", n, (int)n->type->width, (int)n->xoffset); + if(lo != hi && n->xoffset + n->type->width == lo - 2*widthptr) { + // merge with range we already have + lo = n->xoffset; + continue; } + // zero old range + p = zerorange(p, frame, lo, hi, &ax); + + // set new range + hi = n->xoffset + n->type->width; + lo = n->xoffset; } + // zero final range + zerorange(p, frame, lo, hi, &ax); } static Prog* -appendp(Prog *p, int as, int ftype, int32 foffset, int ttype, int32 toffset) +zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *ax) +{ + vlong cnt, i; + + cnt = hi - lo; + if(cnt == 0) + return p; + if(*ax == 0) { + p = appendpp(p, AMOVL, D_CONST, 0, D_AX, 0); + *ax = 1; + } + if(cnt <= 4*widthreg) { + for(i = 0; i < cnt; i += widthreg) { + p = appendpp(p, AMOVL, D_AX, 0, D_SP+D_INDIR, frame+lo+i); + } + } else if(!nacl && cnt <= 128*widthreg) { + p = appendpp(p, ALEAL, D_SP+D_INDIR, frame+lo, D_DI, 0); + p = appendpp(p, ADUFFZERO, D_NONE, 0, D_ADDR, 1*(128-cnt/widthreg)); + p->to.sym = linksym(pkglookup("duffzero", runtimepkg)); + } else { + p = appendpp(p, AMOVL, D_CONST, cnt/widthreg, D_CX, 0); + p = appendpp(p, ALEAL, D_SP+D_INDIR, frame+lo, D_DI, 0); + p = appendpp(p, AREP, D_NONE, 0, D_NONE, 0); + p = appendpp(p, ASTOSL, D_NONE, 0, D_NONE, 0); + } + return p; +} + +static Prog* +appendpp(Prog *p, int as, int ftype, vlong foffset, int ttype, vlong toffset) { Prog *q; - - q = mal(sizeof(*q)); - clearp(q); - q->as = as; - q->lineno = p->lineno; - q->from.type = ftype; - q->from.offset = foffset; - q->to.type = ttype; - q->to.offset = toffset; - q->link = p->link; - p->link = q; - return q; + q = mal(sizeof(*q)); + clearp(q); + q->as = as; + q->lineno = p->lineno; + q->from.type = ftype; + q->from.offset = foffset; + q->to.type = ttype; + q->to.offset = toffset; + q->link = p->link; + p->link = q; + return q; } // Sweep the prog list to mark any used nodes. @@ -71,13 +110,13 @@ void markautoused(Prog* p) { for (; p; p = p->link) { - if (p->as == ATYPE) + if (p->as == ATYPE || p->as == AVARDEF || p->as == AVARKILL) continue; - if (p->from.type == D_AUTO && p->from.node) + if (p->from.node) p->from.node->used = 1; - if (p->to.type == D_AUTO && p->to.node) + if (p->to.node) p->to.node->used = 1; } } @@ -93,6 +132,16 @@ fixautoused(Prog* p) *lp = p->link; continue; } + if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.node && !p->to.node->used) { + // Cannot remove VARDEF instruction, because - unlike TYPE handled above - + // VARDEFs are interspersed with other code, and a jump might be using the + // VARDEF as a target. Replace with a no-op instead. A later pass will remove + // the no-ops. + p->to.type = D_NONE; + p->to.node = N; + p->as = ANOP; + continue; + } if (p->from.type == D_AUTO && p->from.node) p->from.offset += p->from.node->stkdelta; @@ -109,6 +158,7 @@ clearfat(Node *nl) { uint32 w, c, q; Node n1; + Prog *p; /* clear a fat object */ if(debug['g']) @@ -126,21 +176,22 @@ clearfat(Node *nl) agen(nl, &n1); gconreg(AMOVL, 0, D_AX); - if(q >= 4) { + if(q > 128 || (q >= 4 && nacl)) { gconreg(AMOVL, q, D_CX); gins(AREP, N, N); // repeat gins(ASTOSL, N, N); // STOL AL,*(DI)+ + } else if(q >= 4) { + p = gins(ADUFFZERO, N, N); + p->to.type = D_ADDR; + p->to.sym = linksym(pkglookup("duffzero", runtimepkg)); + // 1 and 128 = magic constants: see ../../pkg/runtime/asm_386.s + p->to.offset = 1*(128-q); } else while(q > 0) { gins(ASTOSL, N, N); // STOL AL,*(DI)+ q--; } - if(c >= 4) { - gconreg(AMOVL, c, D_CX); - gins(AREP, N, N); // repeat - gins(ASTOSB, N, N); // STOB AL,*(DI)+ - } else while(c > 0) { gins(ASTOSB, N, N); // STOB AL,*(DI)+ c--; @@ -236,7 +287,9 @@ ginscall(Node *f, int proc) if(proc == 2) { nodreg(®, types[TINT64], D_AX); gins(ATESTL, ®, ®); - patch(gbranch(AJNE, T, -1), retpc); + p = gbranch(AJEQ, T, +1); + cgen_ret(N); + patch(p, pc); } break; } @@ -437,15 +490,15 @@ cgen_ret(Node *n) { Prog *p; - genlist(n->list); // copy out args - if(retpc) { - gjmp(retpc); - return; - } + if(n != N) + genlist(n->list); // copy out args + if(hasdefer) + ginscall(deferreturn, 0); + genlist(curfn->exit); p = gins(ARET, N, N); - if(n->op == ORETJMP) { + if(n != N && n->op == ORETJMP) { p->to.type = D_EXTERN; - p->to.sym = n->left->sym; + p->to.sym = linksym(n->left->sym); } } @@ -663,6 +716,18 @@ dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx) gmove(&t2, &n1); gmove(&t1, ax); p2 = P; + if(nacl) { + // Native Client does not relay the divide-by-zero trap + // to the executing program, so we must insert a check + // for ourselves. + nodconst(&n4, t, 0); + gins(optoas(OCMP, t), &n1, &n4); + p1 = gbranch(optoas(ONE, t), T, +1); + if(panicdiv == N) + panicdiv = sysfunc("panicdivide"); + ginscall(panicdiv, -1); + patch(p1, pc); + } if(check) { nodconst(&n4, t, -1); gins(optoas(OCMP, t), &n1, &n4); @@ -1246,8 +1311,8 @@ expandchecks(Prog *firstp) p->link = p1; p1->lineno = p->lineno; p2->lineno = p->lineno; - p1->loc = 9999; - p2->loc = 9999; + p1->pc = 9999; + p2->pc = 9999; p->as = ACMPL; p->to.type = D_CONST; p->to.offset = 0; diff --git a/src/cmd/8g/gobj.c b/src/cmd/8g/gobj.c index 0517824e0..fa0605e6c 100644 --- a/src/cmd/8g/gobj.c +++ b/src/cmd/8g/gobj.c @@ -32,229 +32,6 @@ #include #include "gg.h" -void -zname(Biobuf *b, Sym *s, int t) -{ - BPUTLE2(b, ANAME); /* as */ - BPUTC(b, t); /* type */ - BPUTC(b, s->sym); /* sym */ - - Bputname(b, s); -} - -void -zfile(Biobuf *b, char *p, int n) -{ - BPUTLE2(b, ANAME); - BPUTC(b, D_FILE); - BPUTC(b, 1); - BPUTC(b, '<'); - Bwrite(b, p, n); - BPUTC(b, 0); -} - -void -zhist(Biobuf *b, int line, vlong offset) -{ - Addr a; - - BPUTLE2(b, AHISTORY); - BPUTLE4(b, line); - zaddr(b, &zprog.from, 0, 0); - a = zprog.to; - if(offset != 0) { - a.offset = offset; - a.type = D_CONST; - } - zaddr(b, &a, 0, 0); -} - -void -zaddr(Biobuf *b, Addr *a, int s, int gotype) -{ - int32 l; - uint64 e; - int i, t; - char *n; - - t = 0; - if(a->index != D_NONE || a->scale != 0) - t |= T_INDEX; - if(s != 0) - t |= T_SYM; - if(gotype != 0) - t |= T_GOTYPE; - - switch(a->type) { - - case D_BRANCH: - if(a->u.branch == nil) - fatal("unpatched branch"); - a->offset = a->u.branch->loc; - - default: - t |= T_TYPE; - - case D_NONE: - if(a->offset != 0) - t |= T_OFFSET; - if(a->offset2 != 0) - t |= T_OFFSET2; - break; - case D_FCONST: - t |= T_FCONST; - break; - case D_SCONST: - t |= T_SCONST; - break; - } - BPUTC(b, t); - - if(t & T_INDEX) { /* implies index, scale */ - BPUTC(b, a->index); - BPUTC(b, a->scale); - } - if(t & T_OFFSET) { /* implies offset */ - l = a->offset; - BPUTLE4(b, l); - } - if(t & T_OFFSET2) { /* implies offset */ - l = a->offset2; - BPUTLE4(b, l); - } - if(t & T_SYM) /* implies sym */ - BPUTC(b, s); - if(t & T_FCONST) { - ieeedtod(&e, a->u.dval); - BPUTLE4(b, e); - BPUTLE4(b, e >> 32); - return; - } - if(t & T_SCONST) { - n = a->u.sval; - for(i=0; itype); - if(t & T_GOTYPE) - BPUTC(b, gotype); -} - -static struct { - struct { Sym *sym; short type; } h[NSYM]; - int sym; -} z; - -static void -zsymreset(void) -{ - for(z.sym=0; z.symsym; - if(i < 0 || i >= NSYM) - i = 0; - if(z.h[i].type == t && z.h[i].sym == s) - return i; - i = z.sym; - s->sym = i; - zname(bout, s, t); - z.h[i].sym = s; - z.h[i].type = t; - if(++z.sym >= NSYM) - z.sym = 1; - *new = 1; - return i; -} - -static int -zsymaddr(Addr *a, int *new) -{ - int t; - - t = a->type; - if(t == D_ADDR) - t = a->index; - return zsym(a->sym, t, new); -} - -void -dumpfuncs(void) -{ - Plist *pl; - int sf, st, gf, gt, new; - Sym *s; - Prog *p; - - zsymreset(); - - // fix up pc - pcloc = 0; - for(pl=plist; pl!=nil; pl=pl->link) { - if(isblank(pl->name)) - continue; - for(p=pl->firstpc; p!=P; p=p->link) { - p->loc = pcloc; - if(p->as != ADATA && p->as != AGLOBL) - pcloc++; - } - } - - // put out functions - for(pl=plist; pl!=nil; pl=pl->link) { - if(isblank(pl->name)) - continue; - - // -S prints code; -SS prints code and data - if(debug['S'] && (pl->name || debug['S']>1)) { - s = S; - if(pl->name != N) - s = pl->name->sym; - print("\n--- prog list \"%S\" ---\n", s); - for(p=pl->firstpc; p!=P; p=p->link) - print("%P\n", p); - } - - for(p=pl->firstpc; p!=P; p=p->link) { - for(;;) { - sf = zsymaddr(&p->from, &new); - gf = zsym(p->from.gotype, D_EXTERN, &new); - if(new && sf == gf) - continue; - st = zsymaddr(&p->to, &new); - if(new && (st == sf || st == gf)) - continue; - gt = zsym(p->to.gotype, D_EXTERN, &new); - if(new && (gt == sf || gt == gf || gt == st)) - continue; - break; - } - - BPUTLE2(bout, p->as); - BPUTLE4(bout, p->lineno); - zaddr(bout, &p->from, sf, gf); - zaddr(bout, &p->to, st, gt); - } - } -} - int dsname(Sym *s, int off, char *t, int n) { @@ -265,7 +42,7 @@ dsname(Sym *s, int off, char *t, int n) p->from.index = D_NONE; p->from.offset = off; p->from.scale = n; - p->from.sym = s; + p->from.sym = linksym(s); p->to.type = D_SCONST; p->to.index = D_NONE; @@ -284,7 +61,7 @@ datastring(char *s, int len, Addr *a) sym = stringsym(s, len); a->type = D_EXTERN; - a->sym = sym; + a->sym = linksym(sym); a->node = sym->def; a->offset = widthptr+4; // skip header a->etype = TINT32; @@ -301,7 +78,7 @@ datagostring(Strlit *sval, Addr *a) sym = stringsym(sval->s, sval->len); a->type = D_EXTERN; - a->sym = sym; + a->sym = linksym(sym); a->node = sym->def; a->offset = 0; // header a->etype = TINT32; @@ -386,7 +163,7 @@ dstringptr(Sym *s, int off, char *str) p = gins(ADATA, N, N); p->from.type = D_EXTERN; p->from.index = D_NONE; - p->from.sym = s; + p->from.sym = linksym(s); p->from.offset = off; p->from.scale = widthptr; @@ -411,7 +188,7 @@ dgostrlitptr(Sym *s, int off, Strlit *lit) p = gins(ADATA, N, N); p->from.type = D_EXTERN; p->from.index = D_NONE; - p->from.sym = s; + p->from.sym = linksym(s); p->from.offset = off; p->from.scale = widthptr; datagostring(lit, &p->to); @@ -439,28 +216,6 @@ dgostringptr(Sym *s, int off, char *str) return dgostrlitptr(s, off, lit); } - -int -duintxx(Sym *s, int off, uint64 v, int wid) -{ - Prog *p; - - off = rnd(off, wid); - - p = gins(ADATA, N, N); - p->from.type = D_EXTERN; - p->from.index = D_NONE; - p->from.sym = s; - p->from.offset = off; - p->from.scale = wid; - p->to.type = D_CONST; - p->to.index = D_NONE; - p->to.offset = v; - off += wid; - - return off; -} - int dsymptr(Sym *s, int off, Sym *x, int xoff) { @@ -471,12 +226,12 @@ dsymptr(Sym *s, int off, Sym *x, int xoff) p = gins(ADATA, N, N); p->from.type = D_EXTERN; p->from.index = D_NONE; - p->from.sym = s; + p->from.sym = linksym(s); p->from.offset = off; p->from.scale = widthptr; p->to.type = D_ADDR; p->to.index = D_EXTERN; - p->to.sym = x; + p->to.sym = linksym(x); p->to.offset = xoff; off += widthptr; diff --git a/src/cmd/8g/gsubr.c b/src/cmd/8g/gsubr.c index 34703ba6e..2f3cb28c8 100644 --- a/src/cmd/8g/gsubr.c +++ b/src/cmd/8g/gsubr.c @@ -48,7 +48,7 @@ clearp(Prog *p) p->from.index = D_NONE; p->to.type = D_NONE; p->to.index = D_NONE; - p->loc = pcloc; + p->pc = pcloc; pcloc++; } @@ -137,7 +137,7 @@ patch(Prog *p, Prog *to) if(p->to.type != D_BRANCH) fatal("patch: not a branch"); p->to.u.branch = to; - p->to.offset = to->loc; + p->to.offset = to->pc; } Prog* @@ -161,13 +161,8 @@ newplist(void) { Plist *pl; - pl = mal(sizeof(*pl)); - if(plist == nil) - plist = pl; - else - plast->link = pl; - plast = pl; - + pl = linknewplist(ctxt); + pc = mal(sizeof(*pc)); clearp(pc); pl->firstpc = pc; @@ -199,8 +194,8 @@ ggloblnod(Node *nam) p = gins(AGLOBL, nam, N); p->lineno = nam->lineno; - p->from.gotype = ngotype(nam); - p->to.sym = S; + p->from.sym->gotype = linksym(ngotype(nam)); + p->to.sym = nil; p->to.type = D_CONST; p->to.offset = nam->type->width; if(nam->readonly) @@ -227,7 +222,7 @@ ggloblsym(Sym *s, int32 width, int dupok, int rodata) p = gins(AGLOBL, N, N); p->from.type = D_EXTERN; p->from.index = D_NONE; - p->from.sym = s; + p->from.sym = linksym(s); p->to.type = D_CONST; p->to.index = D_NONE; p->to.offset = width; @@ -245,7 +240,7 @@ gtrack(Sym *s) p = gins(AUSEFIELD, N, N); p->from.type = D_EXTERN; p->from.index = D_NONE; - p->from.sym = s; + p->from.sym = linksym(s); } int @@ -273,7 +268,7 @@ afunclit(Addr *a, Node *n) if(a->type == D_ADDR && a->index == D_EXTERN) { a->type = D_EXTERN; a->index = D_NONE; - a->sym = n->sym; + a->sym = linksym(n->sym); } } @@ -437,6 +432,7 @@ optoas(int op, Type *t) case CASE(OADD, TINT32): case CASE(OADD, TUINT32): case CASE(OADD, TPTR32): + case CASE(OADDPTR, TPTR32): a = AADDL; break; @@ -1048,6 +1044,7 @@ Node* nodarg(Type *t, int fp) { Node *n; + NodeList *l; Type *first; Iter savet; @@ -1072,6 +1069,14 @@ nodarg(Type *t, int fp) break; case TFIELD: + if(fp == 1 && t->sym != S && !isblanksym(t->sym)) { + for(l=curfn->dcl; l; l=l->next) { + n = l->n; + if((n->class == PPARAM || n->class == PPARAMOUT) && n->sym == t->sym) + return n; + } + } + n = nod(ONAME, N, N); n->type = t->type; n->sym = t->sym; @@ -1692,7 +1697,6 @@ floatmove(Node *f, Node *t) gins(ACMPL, &thi, ncon(0)); p1 = gbranch(AJLT, T, 0); // native - t1.type = types[TINT64]; nodreg(&r1, types[tt], D_F0); gins(AFMOVV, &t1, &r1); if(tt == TFLOAT32) @@ -2178,10 +2182,12 @@ gins(int as, Node *f, Node *t) void naddr(Node *n, Addr *a, int canemitcode) { + Sym *s; + a->scale = 0; a->index = D_NONE; a->type = D_NONE; - a->gotype = S; + a->gotype = nil; a->node = N; if(n == N) return; @@ -2193,12 +2199,12 @@ naddr(Node *n, Addr *a, int canemitcode) case OREGISTER: a->type = n->val.u.reg; - a->sym = S; + a->sym = nil; break; case OINDREG: a->type = n->val.u.reg+D_INDIR; - a->sym = n->sym; + a->sym = linksym(n->sym); a->offset = n->xoffset; break; @@ -2208,20 +2214,22 @@ naddr(Node *n, Addr *a, int canemitcode) a->etype = n->left->type->etype; a->width = n->left->type->width; a->offset = n->xoffset; - a->sym = n->left->sym; + a->sym = linksym(n->left->sym); a->type = D_PARAM; a->node = n->left->orig; break; case OCLOSUREVAR: + if(!curfn->needctxt) + fatal("closurevar without needctxt"); a->type = D_DX+D_INDIR; a->offset = n->xoffset; - a->sym = S; + a->sym = nil; break; case OCFUNC: naddr(n->left, a, canemitcode); - a->sym = n->left->sym; + a->sym = linksym(n->left->sym); break; case ONAME: @@ -2233,17 +2241,17 @@ naddr(Node *n, Addr *a, int canemitcode) a->width = n->type->width; } a->offset = n->xoffset; - a->sym = n->sym; + s = n->sym; a->node = n->orig; //if(a->node >= (Node*)&n) // fatal("stack node"); - if(a->sym == S) - a->sym = lookup(".noname"); + if(s == S) + s = lookup(".noname"); if(n->method) { if(n->type != T) if(n->type->sym != S) if(n->type->sym->pkg != nil) - a->sym = pkglookup(a->sym->name, n->type->sym->pkg); + s = pkglookup(s->name, n->type->sym->pkg); } switch(n->class) { @@ -2262,9 +2270,10 @@ naddr(Node *n, Addr *a, int canemitcode) case PFUNC: a->index = D_EXTERN; a->type = D_ADDR; - a->sym = funcsym(a->sym); + s = funcsym(s); break; } + a->sym = linksym(s); break; case OLITERAL: @@ -2278,7 +2287,7 @@ naddr(Node *n, Addr *a, int canemitcode) break; case CTINT: case CTRUNE: - a->sym = S; + a->sym = nil; a->type = D_CONST; a->offset = mpgetfix(n->val.u.xval); break; @@ -2286,12 +2295,12 @@ naddr(Node *n, Addr *a, int canemitcode) datagostring(n->val.u.sval, a); break; case CTBOOL: - a->sym = S; + a->sym = nil; a->type = D_CONST; a->offset = n->val.u.bval; break; case CTNIL: - a->sym = S; + a->sym = nil; a->type = D_CONST; a->offset = 0; break; @@ -2327,7 +2336,7 @@ naddr(Node *n, Addr *a, int canemitcode) naddr(n->left, a, canemitcode); if(a->type == D_CONST && a->offset == 0) break; // ptr(nil) - a->etype = simtype[TUINTPTR]; + a->etype = simtype[tptr]; a->offset += Array_array; a->width = widthptr; break; diff --git a/src/cmd/8g/list.c b/src/cmd/8g/list.c deleted file mode 100644 index ec02ba5c5..000000000 --- a/src/cmd/8g/list.c +++ /dev/null @@ -1,316 +0,0 @@ -// Derived from Inferno utils/8c/list.c -// http://code.google.com/p/inferno-os/source/browse/utils/8c/list.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 -#include -#include "gg.h" - -static int sconsize; -void -listinit(void) -{ - - fmtinstall('A', Aconv); // as - fmtinstall('P', Pconv); // Prog* - fmtinstall('D', Dconv); // Addr* - fmtinstall('R', Rconv); // reg - fmtinstall('Y', Yconv); // sconst -} - -int -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), "%.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), "%.4d (%L) %-7A %D/%d,%D", - p->loc, p->lineno, p->as, &p->from, sconsize, &p->to); - break; - - case ATEXT: - 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); -} - -int -Dconv(Fmt *fp) -{ - char str[STRINGSZ], s[STRINGSZ]; - Addr *a; - int i; - uint32 d1, d2; - - a = va_arg(fp->args, Addr*); - i = a->type; - if(i >= D_INDIR) { - if(a->offset) - snprint(str, sizeof(str), "%d(%R)", a->offset, i-D_INDIR); - else - snprint(str, sizeof(str), "(%R)", i-D_INDIR); - goto brk; - } - switch(i) { - - default: - if(a->offset) - snprint(str, sizeof(str), "$%d,%R", a->offset, i); - else - snprint(str, sizeof(str), "%R", i); - break; - - case D_NONE: - str[0] = 0; - break; - - case D_BRANCH: - snprint(str, sizeof(str), "%d", a->u.branch->loc); - break; - - case D_EXTERN: - snprint(str, sizeof(str), "%S+%d(SB)", a->sym, a->offset); - break; - - case D_STATIC: - snprint(str, sizeof(str), "%S<>+%d(SB)", a->sym, a->offset); - break; - - case D_AUTO: - snprint(str, sizeof(str), "%S+%d(SP)", a->sym, a->offset); - break; - - case D_PARAM: - snprint(str, sizeof(str), "%S+%d(FP)", a->sym, a->offset); - break; - - case D_CONST: - if(fp->flags & FmtLong) { - d1 = a->offset; - d2 = a->offset2; - snprint(str, sizeof(str), "$%lud-%lud", (ulong)d1, (ulong)d2); - break; - } - snprint(str, sizeof(str), "$%d", a->offset); - break; - - case D_FCONST: - snprint(str, sizeof(str), "$(%.17e)", a->u.dval); - break; - - case D_SCONST: - snprint(str, sizeof(str), "$\"%Y\"", a->u.sval); - break; - - case D_ADDR: - a->type = a->index; - a->index = D_NONE; - snprint(str, sizeof(str), "$%D", a); - a->index = a->type; - a->type = D_ADDR; - goto conv; - } -brk: - if(a->index != D_NONE) { - snprint(s, sizeof(s), "(%R*%d)", (int)a->index, (int)a->scale); - strcat(str, s); - } -conv: - fmtstrcpy(fp, str); - if(a->gotype) - fmtprint(fp, "{%s}", a->gotype->name); - return 0; -} - -static char* regstr[] = -{ - "AL", /* [D_AL] */ - "CL", - "DL", - "BL", - - "AH", /* [D_AH] */ - "CH", - "DH", - "BH", - - "AX", /* [D_AX] */ - "CX", - "DX", - "BX", - "SP", - "BP", - "SI", - "DI", - - "F0", /* [D_F0] */ - "F1", - "F2", - "F3", - "F4", - "F5", - "F6", - "F7", - - "CS", /* [D_CS] */ - "SS", - "DS", - "ES", - "FS", - "GS", - - "GDTR", /* [D_GDTR] */ - "IDTR", /* [D_IDTR] */ - "LDTR", /* [D_LDTR] */ - "MSW", /* [D_MSW] */ - "TASK", /* [D_TASK] */ - - "CR0", /* [D_CR] */ - "CR1", - "CR2", - "CR3", - "CR4", - "CR5", - "CR6", - "CR7", - - "DR0", /* [D_DR] */ - "DR1", - "DR2", - "DR3", - "DR4", - "DR5", - "DR6", - "DR7", - - "TR0", /* [D_TR] */ - "TR1", - "TR2", - "TR3", - "TR4", - "TR5", - "TR6", - "TR7", - - "X0", /* [D_X0] */ - "X1", - "X2", - "X3", - "X4", - "X5", - "X6", - "X7", - - "NONE", /* [D_NONE] */ -}; - -int -Rconv(Fmt *fp) -{ - char str[STRINGSZ]; - int r; - - r = va_arg(fp->args, int); - if(r < 0 || r >= nelem(regstr) || regstr[r] == nil) { - snprint(str, sizeof(str), "BAD_R(%d)", r); - return fmtstrcpy(fp, str); - } - return fmtstrcpy(fp, regstr[r]); -} - -int -Aconv(Fmt *fp) -{ - int i; - - i = va_arg(fp->args, int); - return fmtstrcpy(fp, anames[i]); -} - - -int -Yconv(Fmt *fp) -{ - int i, c; - char str[STRINGSZ], *p, *a; - - a = va_arg(fp->args, char*); - p = str; - for(i=0; i= 'a' && c <= 'z') || - (c >= 'A' && c <= 'Z') || - (c >= '0' && c <= '9')) { - *p++ = c; - continue; - } - *p++ = '\\'; - switch(c) { - default: - if(c < 040 || c >= 0177) - break; /* not portable */ - p[-1] = c; - continue; - case 0: - *p++ = 'z'; - continue; - case '\\': - case '"': - *p++ = c; - continue; - case '\n': - *p++ = 'n'; - continue; - case '\t': - *p++ = 't'; - continue; - } - *p++ = (c>>6) + '0'; - *p++ = ((c>>3) & 7) + '0'; - *p++ = (c & 7) + '0'; - } - *p = 0; - return fmtstrcpy(fp, str); -} diff --git a/src/cmd/8g/opt.h b/src/cmd/8g/opt.h index 0d99bdb97..77a69e13a 100644 --- a/src/cmd/8g/opt.h +++ b/src/cmd/8g/opt.h @@ -109,6 +109,7 @@ EXTERN Bits externs; EXTERN Bits params; EXTERN Bits consts; EXTERN Bits addrs; +EXTERN Bits ivar; EXTERN Bits ovar; EXTERN int change; EXTERN int32 maxnr; @@ -155,8 +156,6 @@ int32 FtoB(int); int BtoR(int32); int BtoF(int32); -#pragma varargck type "D" Adr* - /* * prog.c */ diff --git a/src/cmd/8g/peep.c b/src/cmd/8g/peep.c index 966c0421b..a4e516dd3 100644 --- a/src/cmd/8g/peep.c +++ b/src/cmd/8g/peep.c @@ -107,7 +107,7 @@ peep(Prog *firstp) switch(p->as) { case ALEAL: if(regtyp(&p->to)) - if(p->from.sym != S) + if(p->from.sym != nil) if(p->from.index == D_NONE || p->from.index == D_CONST) conprop(r); break; @@ -387,6 +387,8 @@ subprop(Flow *r0) if(uniqs(r) == nil) break; p = r->prog; + if(p->as == AVARDEF || p->as == AVARKILL) + continue; proginfo(&info, p); if(info.flags & Call) return 0; @@ -478,7 +480,7 @@ copy1(Adr *v1, Adr *v2, Flow *r, int f) if(debug['P']) print("; merge; f=%d", f); } - t = copyu(p, v2, A); + t = copyu(p, v2, nil); switch(t) { case 2: /* rar, can't split */ if(debug['P']) @@ -516,7 +518,7 @@ copy1(Adr *v1, Adr *v2, Flow *r, int f) break; } if(!f) { - t = copyu(p, v1, A); + t = copyu(p, v1, nil); if(!f && (t == 2 || t == 3 || t == 4)) { f = 1; if(debug['P']) @@ -547,7 +549,7 @@ copyu(Prog *p, Adr *v, Adr *s) switch(p->as) { case AJMP: - if(s != A) { + if(s != nil) { if(copysub(&p->to, v, s, 1)) return 1; return 0; @@ -557,7 +559,7 @@ copyu(Prog *p, Adr *v, Adr *s) return 0; case ARET: - if(s != A) + if(s != nil) return 1; return 3; @@ -569,7 +571,7 @@ copyu(Prog *p, Adr *v, Adr *s) if(v->type == p->from.type) return 2; - if(s != A) { + if(s != nil) { if(copysub(&p->to, v, s, 1)) return 1; return 0; @@ -584,6 +586,8 @@ copyu(Prog *p, Adr *v, Adr *s) return 0; } + if(p->as == AVARDEF || p->as == AVARKILL) + return 0; proginfo(&info, p); if((info.reguse|info.regset) & RtoB(v->type)) @@ -599,7 +603,7 @@ copyu(Prog *p, Adr *v, Adr *s) if(info.flags & RightWrite) { if(copyas(&p->to, v)) { - if(s != A) + if(s != nil) return copysub(&p->from, v, s, 1); if(copyau(&p->from, v)) return 4; @@ -608,7 +612,7 @@ copyu(Prog *p, Adr *v, Adr *s) } if(info.flags & (LeftAddr|LeftRead|LeftWrite|RightAddr|RightRead|RightWrite)) { - if(s != A) { + if(s != nil) { if(copysub(&p->from, v, s, 1)) return 1; return copysub(&p->to, v, s, 1); @@ -727,7 +731,7 @@ loop: return; p = r->prog; - t = copyu(p, v0, A); + t = copyu(p, v0, nil); switch(t) { case 0: // miss case 1: // use @@ -743,7 +747,7 @@ loop: if(p->from.node == p0->from.node) if(p->from.offset == p0->from.offset) if(p->from.scale == p0->from.scale) - if(p->from.u.vval == p0->from.u.vval) + if(p->from.type == D_FCONST && p->from.u.dval == p0->from.u.dval) if(p->from.index == p0->from.index) { excise(r); goto loop; diff --git a/src/cmd/8g/prog.c b/src/cmd/8g/prog.c index 14f197b6a..8eed67f6d 100644 --- a/src/cmd/8g/prog.c +++ b/src/cmd/8g/prog.c @@ -38,9 +38,11 @@ static ProgInfo progtable[ALAST] = { [ATEXT]= {Pseudo}, [AFUNCDATA]= {Pseudo}, [APCDATA]= {Pseudo}, - [AUNDEF]= {OK}, + [AUNDEF]= {Break}, [AUSEFIELD]= {OK}, [ACHECKNIL]= {LeftRead}, + [AVARDEF]= {Pseudo | RightWrite}, + [AVARKILL]= {Pseudo | RightWrite}, // NOP is an internal no-op that also stands // for USED and SET annotations, not the Intel opcode. @@ -136,11 +138,16 @@ static ProgInfo progtable[ALAST] = { [AFMOVW]= {SizeW | LeftAddr | RightWrite}, [AFMOVV]= {SizeQ | LeftAddr | RightWrite}, - [AFMOVDP]= {SizeD | LeftRead | RightAddr}, - [AFMOVFP]= {SizeF | LeftRead | RightAddr}, - [AFMOVLP]= {SizeL | LeftRead | RightAddr}, - [AFMOVWP]= {SizeW | LeftRead | RightAddr}, - [AFMOVVP]= {SizeQ | LeftRead | RightAddr}, + // These instructions are marked as RightAddr + // so that the register optimizer does not try to replace the + // memory references with integer register references. + // But they do not use the previous value at the address, so + // we also mark them RightWrite. + [AFMOVDP]= {SizeD | LeftRead | RightWrite | RightAddr}, + [AFMOVFP]= {SizeF | LeftRead | RightWrite | RightAddr}, + [AFMOVLP]= {SizeL | LeftRead | RightWrite | RightAddr}, + [AFMOVWP]= {SizeW | LeftRead | RightWrite | RightAddr}, + [AFMOVVP]= {SizeQ | LeftRead | RightWrite | RightAddr}, [AFMULD]= {SizeD | LeftAddr | RightRdwr}, [AFMULDP]= {SizeD | LeftAddr | RightRdwr}, @@ -193,6 +200,7 @@ static ProgInfo progtable[ALAST] = { [AMOVSB]= {OK, DI|SI, DI|SI}, [AMOVSL]= {OK, DI|SI, DI|SI}, [AMOVSW]= {OK, DI|SI, DI|SI}, + [ADUFFCOPY]= {OK, DI|SI, DI|SI|CX}, [AMOVSD]= {SizeD | LeftRead | RightWrite | Move}, [AMOVSS]= {SizeF | LeftRead | RightWrite | Move}, @@ -285,6 +293,7 @@ static ProgInfo progtable[ALAST] = { [ASTOSB]= {OK, AX|DI, DI}, [ASTOSL]= {OK, AX|DI, DI}, [ASTOSW]= {OK, AX|DI, DI}, + [ADUFFZERO]= {OK, AX|DI, DI}, [ASUBB]= {SizeB | LeftRead | RightRdwr | SetCarry}, [ASUBL]= {SizeL | LeftRead | RightRdwr | SetCarry}, diff --git a/src/cmd/8g/reg.c b/src/cmd/8g/reg.c index a85c6608a..fd610f87a 100644 --- a/src/cmd/8g/reg.c +++ b/src/cmd/8g/reg.c @@ -54,30 +54,6 @@ rcmp(const void *a1, const void *a2) 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); - for(z=0; zopt = nil; return; + } + firstr = (Reg*)g->start; for(r = firstr; r != R; r = (Reg*)r->f.link) { p = r->f.prog; + if(p->as == AVARDEF || p->as == AVARKILL) + continue; proginfo(&info, p); // Avoid making variables for direct-called functions. @@ -227,6 +208,26 @@ regopt(Prog *firstp) if(debug['R'] && debug['v']) dumpit("pass2", &firstr->f, 1); + /* + * pass 2.5 + * iterate propagating fat vardef covering forward + * r->act records vars with a VARDEF since the last CALL. + * (r->act will be reused in pass 5 for something else, + * but we'll be done with it by then.) + */ + active = 0; + for(r = firstr; r != R; r = (Reg*)r->f.link) { + r->f.active = 0; + r->act = zbits; + } + for(r = firstr; r != R; r = (Reg*)r->f.link) { + p = r->f.prog; + if(p->as == AVARDEF && isfat(p->to.node->type) && p->to.node->opt != nil) { + active++; + walkvardef(p->to.node, r, active); + } + } + /* * pass 3 * iterate propagating usage @@ -367,6 +368,8 @@ brk: /* * free aux structures. peep allocates new ones. */ + for(i=0; iopt = nil; flowend(g); firstr = R; @@ -423,6 +426,32 @@ brk: } } +static void +walkvardef(Node *n, Reg *r, int active) +{ + Reg *r1, *r2; + int bn; + Var *v; + + for(r1=r; r1!=R; r1=(Reg*)r1->f.s1) { + if(r1->f.active == active) + break; + r1->f.active = active; + if(r1->f.prog->as == AVARKILL && r1->f.prog->to.node == n) + break; + for(v=n->opt; v!=nil; v=v->nextinnode) { + bn = v - var; + r1->act.b[bn/32] |= 1L << (bn%32); + } + if(r1->f.prog->as == ACALL) + break; + } + + for(r2=r; r2!=r1; r2=(Reg*)r2->f.s1) + if(r2->f.s2 != nil) + walkvardef(n, (Reg*)r2->f.s2, active); +} + /* * add mov b,rn * just after r @@ -436,7 +465,7 @@ addmove(Reg *r, int bn, int rn, int f) p1 = mal(sizeof(*p1)); clearp(p1); - p1->loc = 9999; + p1->pc = 9999; p = r->f.prog; p1->link = p->link; @@ -450,7 +479,7 @@ addmove(Reg *r, int bn, int rn, int f) a->etype = v->etype; a->type = v->name; a->node = v->node; - a->sym = v->node->sym; + a->sym = linksym(v->node->sym); // need to clean this up with wptr and // some of the defaults @@ -618,6 +647,16 @@ mkvar(Reg *r, Adr *a) if(nvar >= NVAR) { if(debug['w'] > 1 && node != N) fatal("variable not optimized: %D", a); + + // If we're not tracking a word in a variable, mark the rest as + // having its address taken, so that we keep the whole thing + // live at all calls. otherwise we might optimize away part of + // a variable but not all of it. + for(i=0; inode == node) + v->addr = 1; + } goto none; } @@ -630,10 +669,13 @@ mkvar(Reg *r, Adr *a) v->width = w; v->addr = flag; // funny punning v->node = node; - - if(debug['R']) - print("bit=%2d et=%2E w=%d+%d %#N %D flag=%d\n", i, et, o, w, node, a, v->addr); - ostats.nvar++; + + // node->opt is the head of a linked list + // of Vars within the given Node, so that + // we can start at a Var and find all the other + // Vars in the same Go variable. + v->nextinnode = node->opt; + node->opt = v; bit = blsh(i); if(n == D_EXTERN || n == D_STATIC) @@ -642,6 +684,46 @@ mkvar(Reg *r, Adr *a) if(n == D_PARAM) for(z=0; zclass == PPARAM) + for(z=0; zclass == PPARAMOUT) + for(z=0; zaddrtaken) + v->addr = 1; + + // Disable registerization for globals, because: + // (1) we might panic at any time and we want the recovery code + // to see the latest values (issue 1304). + // (2) we don't know what pointers might point at them and we want + // loads via those pointers to see updated values and vice versa (issue 7995). + // + // Disable registerization for results if using defer, because the deferred func + // might recover and return, causing the current values to be used. + if(node->class == PEXTERN || (hasdefer && node->class == PPARAMOUT)) + v->addr = 1; + + if(debug['R']) + print("bit=%2d et=%2E w=%d+%d %#N %D flag=%d\n", i, et, o, w, node, a, v->addr); + ostats.nvar++; return bit; @@ -653,7 +735,8 @@ void prop(Reg *r, Bits ref, Bits cal) { Reg *r1, *r2; - int z; + int z, i, j; + Var *v, *v1; for(r1 = r; r1 != R; r1 = (Reg*)r1->f.p1) { for(z=0; zf.prog)) break; + + // Mark all input variables (ivar) as used, because that's what the + // liveness bitmaps say. The liveness bitmaps say that so that a + // panic will not show stale values in the parameter dump. + // Mark variables with a recent VARDEF (r1->act) as used, + // so that the optimizer flushes initializations to memory, + // so that if a garbage collection happens during this CALL, + // the collector will see initialized memory. Again this is to + // match what the liveness bitmaps say. for(z=0; zact.b[z]; ref.b[z] = 0; } + + // cal.b is the current approximation of what's live across the call. + // Every bit in cal.b is a single stack word. For each such word, + // find all the other tracked stack words in the same Go variable + // (struct/slice/string/interface) and mark them live too. + // This is necessary because the liveness analysis for the garbage + // collector works at variable granularity, not at word granularity. + // It is fundamental for slice/string/interface: the garbage collector + // needs the whole value, not just some of the words, in order to + // interpret the other bits correctly. Specifically, slice needs a consistent + // ptr and cap, string needs a consistent ptr and len, and interface + // needs a consistent type word and data word. + for(z=0; z= nvar || ((cal.b[z]>>i)&1) == 0) + continue; + v = var+z*32+i; + if(v->node->opt == nil) // v represents fixed register, not Go variable + continue; + + // v->node->opt is the head of a linked list of Vars + // corresponding to tracked words from the Go variable v->node. + // Walk the list and set all the bits. + // For a large struct this could end up being quadratic: + // after the first setting, the outer loop (for z, i) would see a 1 bit + // for all of the remaining words in the struct, and for each such + // word would go through and turn on all the bits again. + // To avoid the quadratic behavior, we only turn on the bits if + // v is the head of the list or if the head's bit is not yet turned on. + // This will set the bits at most twice, keeping the overall loop linear. + v1 = v->node->opt; + j = v1 - var; + if(v == v1 || ((cal.b[j/32]>>(j&31))&1) == 0) { + for(; v1 != nil; v1 = v1->nextinnode) { + j = v1 - var; + cal.b[j/32] |= 1<<(j&31); + } + } + } + } break; case ATEXT: @@ -691,17 +825,6 @@ prop(Reg *r, Bits ref, Bits cal) ref.b[z] = 0; } break; - - default: - // Work around for issue 1304: - // flush modified globals before each instruction. - for(z=0; zset.b[z]) | @@ -824,18 +947,19 @@ paint1(Reg *r, int bn) r->act.b[z] |= bb; p = r->f.prog; - if(r->use1.b[z] & bb) { - change += CREF * r->f.loop; - if(p->as == AFMOVL || p->as == AFMOVW) - if(BtoR(bb) != D_F0) - change = -CINF; - } - - if((r->use2.b[z]|r->set.b[z]) & bb) { - change += CREF * r->f.loop; - if(p->as == AFMOVL || p->as == AFMOVW) - if(BtoR(bb) != D_F0) - change = -CINF; + if(r->f.prog->as != ANOP) { // don't give credit for NOPs + if(r->use1.b[z] & bb) { + change += CREF * r->f.loop; + if(p->as == AFMOVL || p->as == AFMOVW) + if(BtoR(bb) != D_F0) + change = -CINF; + } + if((r->use2.b[z]|r->set.b[z]) & bb) { + change += CREF * r->f.loop; + if(p->as == AFMOVL || p->as == AFMOVW) + if(BtoR(bb) != D_F0) + change = -CINF; + } } if(STORE(r) & r->regdiff.b[z] & bb) { @@ -877,7 +1001,7 @@ regset(Reg *r, uint32 bb) v = zprog.from; while(b = bb & ~(bb-1)) { v.type = b & 0xFF ? BtoR(b): BtoF(b); - c = copyu(r->f.prog, &v, A); + c = copyu(r->f.prog, &v, nil); if(c == 3) set |= b; bb &= ~b; @@ -896,7 +1020,7 @@ reguse(Reg *r, uint32 bb) v = zprog.from; while(b = bb & ~(bb-1)) { v.type = b & 0xFF ? BtoR(b): BtoF(b); - c = copyu(r->f.prog, &v, A); + c = copyu(r->f.prog, &v, nil); if(c == 1 || c == 2 || c == 4) set |= b; bb &= ~b; @@ -1038,8 +1162,7 @@ paint3(Reg *r, int bn, int32 rb, int rn) void addreg(Adr *a, int rn) { - - a->sym = 0; + a->sym = nil; a->offset = 0; a->type = rn; @@ -1140,15 +1263,15 @@ dumpit(char *str, Flow *r0, int isreg) r1 = r->p2; if(r1 != nil) { print(" pred:"); - for(; r1 != nil; r1 = r->p2link) - print(" %.4ud", r1->prog->loc); + for(; r1 != nil; r1 = r1->p2link) + print(" %.4ud", (int)r1->prog->pc); print("\n"); } // r1 = r->s1; // if(r1 != nil) { // print(" succ:"); // for(; r1 != R; r1 = r1->s1) -// print(" %.4ud", r1->prog->loc); +// print(" %.4ud", (int)r1->prog->pc); // print("\n"); // } } diff --git a/src/cmd/8l/8.out.h b/src/cmd/8l/8.out.h index 988e50f3e..8e642d390 100644 --- a/src/cmd/8l/8.out.h +++ b/src/cmd/8l/8.out.h @@ -547,6 +547,7 @@ enum as APSUBW, APUNPCKHQDQ, APUNPCKLQDQ, + APXOR, ARCPPS, ARCPSS, ARSQRTPS, @@ -578,6 +579,10 @@ enum as AFUNCDATA, APCDATA, ACHECKNIL, + AVARDEF, + AVARKILL, + ADUFFCOPY, + ADUFFZERO, ALAST }; @@ -631,30 +636,23 @@ enum D_X5, D_X6, D_X7, - - D_NONE = 67, - - D_BRANCH = 68, - D_EXTERN = 69, - D_STATIC = 70, - D_AUTO = 71, - D_PARAM = 72, - D_CONST = 73, - D_FCONST = 74, - D_SCONST = 75, - D_ADDR = 76, - - D_FILE, - D_FILE1, + + D_TLS = 67, + D_NONE = 68, + + D_BRANCH = 69, + D_EXTERN = 70, + D_STATIC = 71, + D_AUTO = 72, + D_PARAM = 73, + D_CONST = 74, + D_FCONST = 75, + D_SCONST = 76, + D_ADDR = 77, D_INDIR, /* additive */ D_CONST2 = D_INDIR+D_INDIR, - D_SIZE, /* 8l internal */ - D_PCREL, - D_GOTOFF, - D_GOTREL, - D_TLS, T_TYPE = 1<<0, T_INDEX = 1<<1, @@ -676,15 +674,3 @@ enum * this is the ranlib header */ #define SYMDEF "__.GOSYMDEF" - -/* - * this is the simulated IEEE floating point - */ -typedef struct ieee Ieee; -struct ieee -{ - int32 l; /* contains ls-man 0xffffffff */ - int32 h; /* contains sign 0x80000000 - exp 0x7ff00000 - ms-man 0x000fffff */ -}; diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c index 3be37ea22..114a3eb5d 100644 --- a/src/cmd/8l/asm.c +++ b/src/cmd/8l/asm.c @@ -42,47 +42,20 @@ char freebsddynld[] = "/usr/libexec/ld-elf.so.1"; char openbsddynld[] = "/usr/libexec/ld.so"; char netbsddynld[] = "/usr/libexec/ld.elf_so"; char dragonflydynld[] = "/usr/libexec/ld-elf.so.2"; - -int32 -entryvalue(void) -{ - char *a; - Sym *s; - - a = INITENTRY; - if(*a >= '0' && *a <= '9') - return atolwhex(a); - s = lookup(a, 0); - if(s->type == 0) - return INITTEXT; - if(s->type != STEXT) - diag("entry not text: %s", s->name); - return s->value; -} - -vlong -datoff(vlong addr) -{ - 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; -} +char solarisdynld[] = "/lib/ld.so.1"; static int needlib(char *name) { char *p; - Sym *s; + LSym *s; if(*name == '\0') return 0; /* reuse hash code in symbol table */ p = smprint(".dynlib.%s", name); - s = lookup(p, 0); + s = linklookup(ctxt, p, 0); free(p); if(s->type == 0) { s->type = 100; // avoid SDATA, etc. @@ -93,11 +66,11 @@ needlib(char *name) int nelfsym = 1; -static void addpltsym(Sym*); -static void addgotsym(Sym*); +static void addpltsym(Link*, LSym*); +static void addgotsym(Link*, LSym*); void -adddynrela(Sym *rela, Sym *s, Reloc *r) +adddynrela(LSym *rela, LSym *s, Reloc *r) { USED(rela); USED(s); @@ -106,12 +79,12 @@ adddynrela(Sym *rela, Sym *s, Reloc *r) } void -adddynrel(Sym *s, Reloc *r) +adddynrel(LSym *s, Reloc *r) { - Sym *targ, *rel, *got; + LSym *targ, *rel, *got; targ = r->sym; - cursym = s; + ctxt->cursym = s; switch(r->type) { default: @@ -127,16 +100,16 @@ adddynrel(Sym *s, Reloc *r) 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->type = R_PCREL; r->add += 4; return; case 256 + R_386_PLT32: - r->type = D_PCREL; + r->type = R_PCREL; r->add += 4; if(targ->type == SDYNIMPORT) { - addpltsym(targ); - r->sym = lookup(".plt", 0); + addpltsym(ctxt, targ); + r->sym = linklookup(ctxt, ".plt", 0); r->add += targ->plt; } return; @@ -150,46 +123,46 @@ adddynrel(Sym *s, Reloc *r) return; } s->p[r->off-2] = 0x8d; - r->type = D_GOTOFF; + r->type = R_GOTOFF; return; } - addgotsym(targ); - r->type = D_CONST; // write r->add during relocsym + addgotsym(ctxt, targ); + r->type = R_CONST; // write r->add during relocsym r->sym = S; r->add += targ->got; return; case 256 + R_386_GOTOFF: - r->type = D_GOTOFF; + r->type = R_GOTOFF; return; case 256 + R_386_GOTPC: - r->type = D_PCREL; - r->sym = lookup(".got", 0); + r->type = R_PCREL; + r->sym = linklookup(ctxt, ".got", 0); r->add += 4; return; case 256 + R_386_32: if(targ->type == SDYNIMPORT) diag("unexpected R_386_32 relocation for dynamic symbol %s", targ->name); - r->type = D_ADDR; + r->type = R_ADDR; return; case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 0: - r->type = D_ADDR; + r->type = R_ADDR; if(targ->type == SDYNIMPORT) diag("unexpected reloc for dynamic symbol %s", targ->name); return; case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 1: if(targ->type == SDYNIMPORT) { - addpltsym(targ); - r->sym = lookup(".plt", 0); + addpltsym(ctxt, targ); + r->sym = linklookup(ctxt, ".plt", 0); r->add = targ->plt; - r->type = D_PCREL; + r->type = R_PCREL; return; } - r->type = D_PCREL; + r->type = R_PCREL; return; case 512 + MACHO_FAKE_GOTPCREL: @@ -201,13 +174,13 @@ adddynrel(Sym *s, Reloc *r) return; } s->p[r->off-2] = 0x8d; - r->type = D_PCREL; + r->type = R_PCREL; return; } - addgotsym(targ); - r->sym = lookup(".got", 0); + addgotsym(ctxt, targ); + r->sym = linklookup(ctxt, ".got", 0); r->add += targ->got; - r->type = D_PCREL; + r->type = R_PCREL; return; } @@ -216,21 +189,22 @@ adddynrel(Sym *s, Reloc *r) return; switch(r->type) { - case D_PCREL: - addpltsym(targ); - r->sym = lookup(".plt", 0); + case R_CALL: + case R_PCREL: + addpltsym(ctxt, targ); + r->sym = linklookup(ctxt, ".plt", 0); r->add = targ->plt; return; - case D_ADDR: + case R_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 + adddynsym(ctxt, targ); + rel = linklookup(ctxt, ".rel", 0); + addaddrplus(ctxt, rel, s, r->off); + adduint32(ctxt, rel, ELF32_R_INFO(targ->dynid, R_386_32)); + r->type = R_CONST; // write r->add during relocsym r->sym = S; return; } @@ -245,22 +219,22 @@ adddynrel(Sym *s, Reloc *r) // 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); + adddynsym(ctxt, targ); + got = linklookup(ctxt, ".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); + adduint32(ctxt, got, 0); + adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), targ->dynid); r->type = 256; // ignore during relocsym return; } break; } - cursym = s; + ctxt->cursym = s; diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type); } @@ -276,21 +250,23 @@ elfreloc1(Reloc *r, vlong sectoff) default: return -1; - case D_ADDR: + case R_ADDR: if(r->siz == 4) LPUT(R_386_32 | elfsym<<8); else return -1; break; - case D_PCREL: + case R_CALL: + case R_PCREL: if(r->siz == 4) LPUT(R_386_PC32 | elfsym<<8); else return -1; break; - case D_TLS: + case R_TLS_LE: + case R_TLS_IE: if(r->siz == 4) LPUT(R_386_TLS_LE | elfsym<<8); else @@ -304,7 +280,7 @@ int machoreloc1(Reloc *r, vlong sectoff) { uint32 v; - Sym *rs; + LSym *rs; rs = r->xsym; @@ -326,10 +302,11 @@ machoreloc1(Reloc *r, vlong sectoff) switch(r->type) { default: return -1; - case D_ADDR: + case R_ADDR: v |= MACHO_GENERIC_RELOC_VANILLA<<28; break; - case D_PCREL: + case R_CALL: + case R_PCREL: v |= 1<<24; // pc-relative bit v |= MACHO_GENERIC_RELOC_VANILLA<<28; break; @@ -358,17 +335,17 @@ machoreloc1(Reloc *r, vlong sectoff) } int -archreloc(Reloc *r, Sym *s, vlong *val) +archreloc(Reloc *r, LSym *s, vlong *val) { USED(s); if(linkmode == LinkExternal) return -1; switch(r->type) { - case D_CONST: + case R_CONST: *val = r->add; return 0; - case D_GOTOFF: - *val = symaddr(r->sym) + r->add - symaddr(lookup(".got", 0)); + case R_GOTOFF: + *val = symaddr(r->sym) + r->add - symaddr(linklookup(ctxt, ".got", 0)); return 0; } return -1; @@ -377,119 +354,119 @@ archreloc(Reloc *r, Sym *s, vlong *val) void elfsetupplt(void) { - Sym *plt, *got; + LSym *plt, *got; - plt = lookup(".plt", 0); - got = lookup(".got.plt", 0); + plt = linklookup(ctxt, ".plt", 0); + got = linklookup(ctxt, ".got.plt", 0); if(plt->size == 0) { // pushl got+4 - adduint8(plt, 0xff); - adduint8(plt, 0x35); - addaddrplus(plt, got, 4); + adduint8(ctxt, plt, 0xff); + adduint8(ctxt, plt, 0x35); + addaddrplus(ctxt, plt, got, 4); // jmp *got+8 - adduint8(plt, 0xff); - adduint8(plt, 0x25); - addaddrplus(plt, got, 8); + adduint8(ctxt, plt, 0xff); + adduint8(ctxt, plt, 0x25); + addaddrplus(ctxt, plt, got, 8); // zero pad - adduint32(plt, 0); + adduint32(ctxt, plt, 0); // assume got->size == 0 too - addaddrplus(got, lookup(".dynamic", 0), 0); - adduint32(got, 0); - adduint32(got, 0); + addaddrplus(ctxt, got, linklookup(ctxt, ".dynamic", 0), 0); + adduint32(ctxt, got, 0); + adduint32(ctxt, got, 0); } } static void -addpltsym(Sym *s) +addpltsym(Link *ctxt, LSym *s) { - Sym *plt, *got, *rel; + LSym *plt, *got, *rel; if(s->plt >= 0) return; - adddynsym(s); + adddynsym(ctxt, s); if(iself) { - plt = lookup(".plt", 0); - got = lookup(".got.plt", 0); - rel = lookup(".rel.plt", 0); + plt = linklookup(ctxt, ".plt", 0); + got = linklookup(ctxt, ".got.plt", 0); + rel = linklookup(ctxt, ".rel.plt", 0); if(plt->size == 0) elfsetupplt(); // jmpq *got+size - adduint8(plt, 0xff); - adduint8(plt, 0x25); - addaddrplus(plt, got, got->size); + adduint8(ctxt, plt, 0xff); + adduint8(ctxt, plt, 0x25); + addaddrplus(ctxt, plt, got, got->size); // add to got: pointer to current pos in plt - addaddrplus(got, plt, plt->size); + addaddrplus(ctxt, got, plt, plt->size); // pushl $x - adduint8(plt, 0x68); - adduint32(plt, rel->size); + adduint8(ctxt, plt, 0x68); + adduint32(ctxt, plt, rel->size); // jmp .plt - adduint8(plt, 0xe9); - adduint32(plt, -(plt->size+4)); + adduint8(ctxt, plt, 0xe9); + adduint32(ctxt, plt, -(plt->size+4)); // rel - addaddrplus(rel, got, got->size-4); - adduint32(rel, ELF32_R_INFO(s->dynid, R_386_JMP_SLOT)); + addaddrplus(ctxt, rel, got, got->size-4); + adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_386_JMP_SLOT)); s->plt = plt->size - 16; } else if(HEADTYPE == Hdarwin) { // Same laziness as in 6l. - Sym *plt; + LSym *plt; - plt = lookup(".plt", 0); + plt = linklookup(ctxt, ".plt", 0); - addgotsym(s); + addgotsym(ctxt, s); - adduint32(lookup(".linkedit.plt", 0), s->dynid); + adduint32(ctxt, linklookup(ctxt, ".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); + adduint8(ctxt, plt, 0xff); + adduint8(ctxt, plt, 0x25); + addaddrplus(ctxt, plt, linklookup(ctxt, ".got", 0), s->got); } else { diag("addpltsym: unsupported binary format"); } } static void -addgotsym(Sym *s) +addgotsym(Link *ctxt, LSym *s) { - Sym *got, *rel; + LSym *got, *rel; if(s->got >= 0) return; - adddynsym(s); - got = lookup(".got", 0); + adddynsym(ctxt, s); + got = linklookup(ctxt, ".got", 0); s->got = got->size; - adduint32(got, 0); + adduint32(ctxt, got, 0); if(iself) { - rel = lookup(".rel", 0); - addaddrplus(rel, got, s->got); - adduint32(rel, ELF32_R_INFO(s->dynid, R_386_GLOB_DAT)); + rel = linklookup(ctxt, ".rel", 0); + addaddrplus(ctxt, rel, got, s->got); + adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_386_GLOB_DAT)); } else if(HEADTYPE == Hdarwin) { - adduint32(lookup(".linkedit.got", 0), s->dynid); + adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), s->dynid); } else { diag("addgotsym: unsupported binary format"); } } void -adddynsym(Sym *s) +adddynsym(Link *ctxt, LSym *s) { - Sym *d; + LSym *d; int t; char *name; @@ -499,20 +476,20 @@ adddynsym(Sym *s) if(iself) { s->dynid = nelfsym++; - d = lookup(".dynsym", 0); + d = linklookup(ctxt, ".dynsym", 0); /* name */ name = s->extname; - adduint32(d, addstring(lookup(".dynstr", 0), name)); + adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name)); /* value */ if(s->type == SDYNIMPORT) - adduint32(d, 0); + adduint32(ctxt, d, 0); else - addaddr(d, s); + addaddr(ctxt, d, s); /* size */ - adduint32(d, 0); + adduint32(ctxt, d, 0); /* type */ t = STB_GLOBAL << 4; @@ -520,12 +497,12 @@ adddynsym(Sym *s) t |= STT_FUNC; else t |= STT_OBJECT; - adduint8(d, t); - adduint8(d, 0); + adduint8(ctxt, d, t); + adduint8(ctxt, d, 0); /* shndx */ if(s->type == SDYNIMPORT) - adduint16(d, SHN_UNDEF); + adduint16(ctxt, d, SHN_UNDEF); else { switch(s->type) { default: @@ -542,7 +519,7 @@ adddynsym(Sym *s) t = 14; break; } - adduint16(d, t); + adduint16(ctxt, d, t); } } else if(HEADTYPE == Hdarwin) { diag("adddynsym: missed symbol %s (%s)", s->name, s->extname); @@ -556,16 +533,16 @@ adddynsym(Sym *s) void adddynlib(char *lib) { - Sym *s; + LSym *s; if(!needlib(lib)) return; if(iself) { - s = lookup(".dynstr", 0); + s = linklookup(ctxt, ".dynstr", 0); if(s->size == 0) addstring(s, ""); - elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib)); + elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib)); } else if(HEADTYPE == Hdarwin) { machoadddynlib(lib); } else if(HEADTYPE != Hwindows) { @@ -576,10 +553,10 @@ adddynlib(char *lib) void asmb(void) { - int32 v, magic; + int32 magic; uint32 symo, dwarfoff, machlink; Section *sect; - Sym *sym; + LSym *sym; int i; if(debug['v']) @@ -641,18 +618,7 @@ asmb(void) default: if(iself) goto Elfsym; - case Hgarbunix: - symo = rnd(HEADR+segtext.filelen, 8192)+segdata.filelen; - break; - case Hunixcoff: - symo = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen; - break; - case Hplan9x32: - symo = HEADR+segtext.filelen+segdata.filelen; - break; - case Hmsdoscom: - case Hmsdosexe: - debug['s'] = 1; + case Hplan9: symo = HEADR+segtext.filelen+segdata.filelen; break; case Hdarwin: @@ -685,11 +651,11 @@ asmb(void) elfemitreloc(); } break; - case Hplan9x32: + case Hplan9: asmplan9sym(); cflush(); - sym = lookup("pclntab", 0); + sym = linklookup(ctxt, "pclntab", 0); if(sym != nil) { lcsize = sym->np; for(i=0; i < lcsize; i++) @@ -715,96 +681,7 @@ asmb(void) cseek(0L); switch(HEADTYPE) { default: - case Hgarbunix: /* garbage */ - lputb(0x160L<<16); /* magic and sections */ - lputb(0L); /* time and date */ - lputb(rnd(HEADR+segtext.filelen, 4096)+segdata.filelen); - lputb(symsize); /* nsyms */ - lputb((0x38L<<16)|7L); /* size of optional hdr and flags */ - lputb((0413<<16)|0437L); /* magic and version */ - lputb(rnd(HEADR+segtext.filelen, 4096)); /* sizes */ - lputb(segdata.filelen); - lputb(segdata.len - segdata.filelen); - lputb(entryvalue()); /* va of entry */ - lputb(INITTEXT-HEADR); /* va of base of text */ - lputb(segdata.vaddr); /* va of base of data */ - lputb(segdata.vaddr+segdata.filelen); /* va of base of bss */ - lputb(~0L); /* gp reg mask */ - lputb(0L); - lputb(0L); - lputb(0L); - lputb(0L); - lputb(~0L); /* gp value ?? */ - break; - case Hunixcoff: /* unix coff */ - /* - * file header - */ - lputl(0x0004014c); /* 4 sections, magic */ - lputl(0); /* unix time stamp */ - lputl(0); /* symbol table */ - lputl(0); /* nsyms */ - lputl(0x0003001c); /* flags, sizeof a.out header */ - /* - * a.out header - */ - lputl(0x10b); /* magic, version stamp */ - lputl(rnd(segtext.filelen, INITRND)); /* text sizes */ - lputl(segdata.filelen); /* data sizes */ - lputl(segdata.len - segdata.filelen); /* bss sizes */ - lputb(entryvalue()); /* va of entry */ - lputl(INITTEXT); /* text start */ - lputl(segdata.vaddr); /* data start */ - /* - * text section header - */ - s8put(".text"); - lputl(HEADR); /* pa */ - lputl(HEADR); /* va */ - lputl(segtext.filelen); /* text size */ - lputl(HEADR); /* file offset */ - lputl(0); /* relocation */ - lputl(0); /* line numbers */ - lputl(0); /* relocation, line numbers */ - lputl(0x20); /* flags text only */ - /* - * data section header - */ - s8put(".data"); - 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 */ - lputl(0x40); /* flags data only */ - /* - * bss section header - */ - s8put(".bss"); - 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 */ - lputl(0); /* relocation, line numbers */ - lputl(0x80); /* flags bss only */ - /* - * comment section header - */ - s8put(".comment"); - lputl(0); /* pa */ - lputl(0); /* va */ - lputl(symsize+lcsize); /* comment size */ - 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 Hplan9x32: /* plan9 */ + case Hplan9: /* plan9 */ magic = 4*11*11+7; lputb(magic); /* magic */ lputb(segtext.filelen); /* sizes */ @@ -815,31 +692,6 @@ asmb(void) lputb(spsize); /* sp offsets */ lputb(lcsize); /* line offsets */ break; - case Hmsdoscom: - /* MS-DOS .COM */ - break; - case Hmsdosexe: - /* fake MS-DOS .EXE */ - 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 */ - wputl(0x0000); /* number of reloc items */ - v = rnd(HEADR-(INITTEXT & 0xFFFF), 16); - wputl(v/16); /* size of header */ - wputl(0x0000); /* minimum allocation */ - wputl(0xFFFF); /* maximum allocation */ - wputl(0x0000); /* initial ss value */ - wputl(0x0100); /* initial sp value */ - wputl(0x0000); /* complemented checksum */ - v = entryvalue(); - wputl(v); /* initial ip value (!) */ - wputl(0x0000); /* initial cs value */ - wputl(0x0000); - wputl(0x0000); - wputl(0x003E); /* reloc table offset */ - wputl(0x0000); /* overlay number */ - break; case Hdarwin: asmbmacho(); break; @@ -848,6 +700,7 @@ asmb(void) case Hnetbsd: case Hopenbsd: case Hdragonfly: + case Hnacl: asmbelf(symo); break; case Hwindows: diff --git a/src/cmd/8l/l.h b/src/cmd/8l/l.h index 814aa1458..c9695ade0 100644 --- a/src/cmd/8l/l.h +++ b/src/cmd/8l/l.h @@ -31,6 +31,7 @@ #include #include #include +#include #include "8.out.h" #ifndef EXTERN @@ -42,141 +43,14 @@ enum thechar = '8', PtrSize = 4, IntSize = 4, + RegSize = 4, MaxAlign = 32, // max data alignment FuncAlign = 16 }; #define P ((Prog*)0) -#define S ((Sym*)0) -#define TNAME (cursym?cursym->name:noname) - -typedef struct Adr Adr; -typedef struct Prog Prog; -typedef struct Sym Sym; -typedef struct Auto Auto; -typedef struct Optab Optab; -typedef struct Reloc Reloc; - -struct Adr -{ - union - { - int32 u0offset; - char u0scon[8]; - Prog *u0cond; /* not used, but should be D_BRANCH */ - Ieee u0ieee; - char *u0sbig; - } u0; - Sym* sym; - short type; - uchar index; - char scale; - int32 offset2; -}; - -#define offset u0.u0offset -#define scon u0.u0scon -#define cond u0.u0cond -#define ieee u0.u0ieee -#define sbig u0.u0sbig - -struct Reloc -{ - int32 off; - uchar siz; - uchar done; - int32 type; - int32 add; - int32 xadd; - Sym* sym; - Sym* xsym; -}; - -struct Prog -{ - Adr from; - Adr to; - Prog* forwd; - Prog* comefrom; - Prog* link; - Prog* pcond; /* work on this */ - int32 pc; - int32 spadj; - int32 line; - short as; - char width; /* fake for DATA */ - char ft; /* oclass cache */ - char tt; - uchar mark; /* work on these */ - uchar back; - uchar bigjmp; -}; -#define datasize from.scale -#define textflag from.scale -#define iscall(p) ((p)->as == ACALL) - -struct Auto -{ - Sym* asym; - Auto* link; - int32 aoffset; - short type; - Sym* gotype; -}; -struct Sym -{ - char* name; - char* extname; // name used in external object files - short type; - short version; - uchar dupok; - uchar reachable; - uchar cgoexport; - uchar special; - uchar stkcheck; - uchar hide; - int32 value; - int32 size; - int32 sig; - int32 dynid; - int32 plt; - int32 got; - int32 align; // if non-zero, required alignment in bytes - int32 elfsym; - int32 args; // size of stack frame incoming arguments area - Sym* hash; // in hash table - Sym* allsym; // in all symbol list - Sym* next; // in text or data list - Sym* sub; // in sub list - Sym* outer; // container of sub - Sym* gotype; - Sym* reachparent; - Sym* queue; - char* file; - char* dynimplib; - char* dynimpvers; - struct Section* sect; - struct Hist* hist; // for ATEXT - - // STEXT - Auto* autom; - Prog* text; - - // SDATA, SBSS - uchar* p; - int32 np; - int32 maxp; - Reloc* r; - int32 nr; - int32 maxr; -}; -struct Optab -{ - short as; - uchar* ytab; - uchar prefix; - uchar op[13]; -}; +#define S ((LSym*)0) +#define TNAME (ctxt->cursym?ctxt->cursym->name:noname) enum { @@ -185,202 +59,36 @@ enum MINLC = 1, MAXIO = 8192, MAXHIST = 40, /* limit of path elements for history symbols */ - - Yxxx = 0, - Ynone, - Yi0, - Yi1, - Yi8, - Yi32, - Yiauto, - Yal, - Ycl, - Yax, - Ycx, - Yrb, - Yrl, - Yrf, - Yf0, - Yrx, - Ymb, - Yml, - Ym, - Ybr, - Ycol, - - Ycs, Yss, Yds, Yes, Yfs, Ygs, - Ygdtr, Yidtr, Yldtr, Ymsw, Ytask, - Ycr0, Ycr1, Ycr2, Ycr3, Ycr4, Ycr5, Ycr6, Ycr7, - Ydr0, Ydr1, Ydr2, Ydr3, Ydr4, Ydr5, Ydr6, Ydr7, - Ytr0, Ytr1, Ytr2, Ytr3, Ytr4, Ytr5, Ytr6, Ytr7, - Ymr, Ymm, - Yxr, Yxm, - Ymax, - - Zxxx = 0, - - Zlit, - Zlitm_r, - Z_rp, - Zbr, - Zcall, - Zcallcon, - Zcallind, - Zib_, - Zib_rp, - Zibo_m, - Zil_, - Zil_rp, - Zilo_m, - Zjmp, - Zjmpcon, - Zloop, - Zm_o, - Zm_r, - Zm2_r, - Zm_r_xm, - Zm_r_i_xm, - Zaut_r, - Zo_m, - Zpseudo, - Zr_m, - Zr_m_xm, - Zr_m_i_xm, - Zrp_, - Z_ib, - Z_il, - Zm_ibo, - Zm_ilo, - Zib_rr, - Zil_rr, - Zclr, - Zibm_r, /* mmx1,mmx2/mem64,imm8 */ - Zbyte, - Zmov, - Zmax, - - Px = 0, - Pe = 0x66, /* operand escape */ - Pm = 0x0f, /* 2byte opcode escape */ - Pq = 0xff, /* both escape */ - Pb = 0xfe, /* byte operands */ - Pf2 = 0xf2, /* xmm escape 1 */ - Pf3 = 0xf3, /* xmm escape 2 */ }; -#pragma varargck type "A" int -#pragma varargck type "D" Adr* #pragma varargck type "I" uchar* -#pragma varargck type "P" Prog* -#pragma varargck type "R" int -#pragma varargck type "S" char* -#pragma varargck type "Y" Sym* -#pragma varargck type "Z" char* -#pragma varargck type "i" char* -EXTERN int32 HEADR; -EXTERN int32 HEADTYPE; -EXTERN int32 INITRND; -EXTERN int32 INITTEXT; -EXTERN int32 INITDAT; -EXTERN char* INITENTRY; /* entry point */ -EXTERN char* pcstr; -EXTERN Auto* curauto; -EXTERN Auto* curhist; -EXTERN Prog* curp; -EXTERN Sym* cursym; -EXTERN Sym* datap; +EXTERN LSym* datap; EXTERN int debug[128]; EXTERN char literal[32]; -EXTERN Sym* etextp; EXTERN Prog* firstp; -EXTERN uchar ycover[Ymax*Ymax]; -EXTERN uchar* andptr; -EXTERN uchar and[100]; -EXTERN char reg[D_NONE]; EXTERN int32 lcsize; -EXTERN int maxop; -EXTERN int nerrors; -EXTERN char* noname; -EXTERN int32 pc; EXTERN char* rpath; EXTERN int32 spsize; -EXTERN Sym* symlist; +EXTERN LSym* symlist; EXTERN int32 symsize; -EXTERN Sym* textp; EXTERN int32 textsize; -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 Optab optab[]; -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); -Prog* appendp(Prog*); +int Iconv(Fmt *fp); +void adddynlib(char *lib); +void adddynrel(LSym *s, Reloc *r); +void adddynrela(LSym *rela, LSym *s, Reloc *r); +void adddynsym(Link *ctxt, LSym *s); +int archreloc(Reloc *r, LSym *s, vlong *val); void asmb(void); -void asmdyn(void); -void asmins(Prog*); -void asmsym(void); -int32 atolwhex(char*); -Prog* brchain(Prog*); -Prog* brloop(Prog*); -void cflush(void); -Prog* copyp(Prog*); -vlong cpos(void); -double cputime(void); -void diag(char*, ...); -void dodata(void); -void doelf(void); -void doprof1(void); -void doprof2(void); -void dostkoff(void); -int32 entryvalue(void); -void follow(void); -void instinit(void); +int elfreloc1(Reloc *r, vlong sectoff); +void elfsetupplt(void); void listinit(void); -Sym* lookup(char*, int); -void lputb(int32); -void lputl(int32); -void vputl(uint64); -void strnput(char*, int); -void main(int, char*[]); -void* mal(uint32); -int opsize(Prog*); -void patch(void); -Prog* prg(void); -int relinv(int); -int32 rnd(int32, int32); -void s8put(char*); -void span(void); -void undef(void); -int32 symaddr(Sym*); -void wput(ushort); -void wputl(ushort); -void xdefine(char*, int, int32); - -uint32 machheadr(void); -vlong addaddr(Sym *s, Sym *t); -vlong addsize(Sym *s, Sym *t); -vlong addstring(Sym *s, char *str); -vlong adduint16(Sym *s, uint16 v); -vlong adduint32(Sym *s, uint32 v); -vlong adduint64(Sym *s, uint64 v); -vlong adduint8(Sym *s, uint8 v); -vlong adduintxx(Sym *s, uint64 v, int wid); - -/* - * go.c - */ -void deadcode(void); +int machoreloc1(Reloc *r, vlong sectoff); +void main(int argc, char *argv[]); +int32 rnd(int32 v, int32 r); +void s8put(char *n); +char* xsymname(LSym *s); /* Native is little-endian */ #define LPUT(a) lputl(a) diff --git a/src/cmd/8l/list.c b/src/cmd/8l/list.c index e2a2ec5ed..0a7534060 100644 --- a/src/cmd/8l/list.c +++ b/src/cmd/8l/list.c @@ -36,297 +36,10 @@ void listinit(void) { - - fmtinstall('R', Rconv); - fmtinstall('A', Aconv); - fmtinstall('D', Dconv); - fmtinstall('S', Sconv); - fmtinstall('P', Pconv); + listinit8(); fmtinstall('I', Iconv); } -static Prog *bigP; - -int -Pconv(Fmt *fp) -{ - Prog *p; - - p = va_arg(fp->args, Prog*); - bigP = p; - switch(p->as) { - case ATEXT: - if(p->from.scale) { - fmtprint(fp, "(%d) %A %D,%d,%D", - p->line, p->as, &p->from, p->from.scale, &p->to); - break; - } - default: - fmtprint(fp, "(%d) %A %D,%D", - p->line, p->as, &p->from, &p->to); - break; - case ADATA: - 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 0; -} - -int -Aconv(Fmt *fp) -{ - int i; - - i = va_arg(fp->args, int); - return fmtstrcpy(fp, anames[i]); -} - -char* -xsymname(Sym *s) -{ - if(s == nil) - return "!!noname!!"; - return s->name; -} - -int -Dconv(Fmt *fp) -{ - char str[STRINGSZ], s[STRINGSZ]; - Adr *a; - int i; - - a = va_arg(fp->args, Adr*); - i = a->type; - if(i >= D_INDIR && i < 2*D_INDIR) { - if(a->offset) - snprint(str, sizeof str, "%d(%R)", a->offset, i-D_INDIR); - else - snprint(str, sizeof str, "(%R)", i-D_INDIR); - goto brk; - } - switch(i) { - - default: - snprint(str, sizeof str, "%R", i); - break; - - case D_NONE: - str[0] = 0; - break; - - case D_BRANCH: - if(bigP != P && bigP->pcond != P) - if(a->sym != S) - snprint(str, sizeof str, "%ux+%s", bigP->pcond->pc, - a->sym->name); - else - snprint(str, sizeof str, "%ux", bigP->pcond->pc); - else - snprint(str, sizeof str, "%d(PC)", a->offset); - break; - - case D_EXTERN: - snprint(str, sizeof str, "%s+%d(SB)", xsymname(a->sym), a->offset); - break; - - case D_STATIC: - snprint(str, sizeof str, "%s<%d>+%d(SB)", xsymname(a->sym), - a->sym->version, a->offset); - break; - - case D_AUTO: - snprint(str, sizeof str, "%s+%d(SP)", xsymname(a->sym), a->offset); - break; - - case D_PARAM: - if(a->sym) - snprint(str, sizeof str, "%s+%d(FP)", a->sym->name, a->offset); - else - snprint(str, sizeof str, "%d(FP)", a->offset); - break; - - case D_CONST: - snprint(str, sizeof str, "$%d", a->offset); - break; - - case D_CONST2: - snprint(str, sizeof str, "$%d-%d", a->offset, a->offset2); - break; - - case D_FCONST: - snprint(str, sizeof str, "$(%.8ux,%.8ux)", a->ieee.h, a->ieee.l); - break; - - case D_SCONST: - snprint(str, sizeof str, "$\"%S\"", a->scon); - break; - - case D_ADDR: - a->type = a->index; - a->index = D_NONE; - snprint(str, sizeof str, "$%D", a); - a->index = a->type; - a->type = D_ADDR; - goto conv; - } -brk: - if(a->index != D_NONE) { - sprint(s, "(%R*%d)", (int)a->index, a->scale); - strcat(str, s); - } -conv: - fmtstrcpy(fp, str); -// if(a->gotype) -// fmtprint(fp, "«%s»", a->gotype->name); - return 0; -} - -char* regstr[] = -{ - "AL", /* [D_AL] */ - "CL", - "DL", - "BL", - "AH", - "CH", - "DH", - "BH", - - "AX", /* [D_AX] */ - "CX", - "DX", - "BX", - "SP", - "BP", - "SI", - "DI", - - "F0", /* [D_F0] */ - "F1", - "F2", - "F3", - "F4", - "F5", - "F6", - "F7", - - "CS", /* [D_CS] */ - "SS", - "DS", - "ES", - "FS", - "GS", - - "GDTR", /* [D_GDTR] */ - "IDTR", /* [D_IDTR] */ - "LDTR", /* [D_LDTR] */ - "MSW", /* [D_MSW] */ - "TASK", /* [D_TASK] */ - - "CR0", /* [D_CR] */ - "CR1", - "CR2", - "CR3", - "CR4", - "CR5", - "CR6", - "CR7", - - "DR0", /* [D_DR] */ - "DR1", - "DR2", - "DR3", - "DR4", - "DR5", - "DR6", - "DR7", - - "TR0", /* [D_TR] */ - "TR1", - "TR2", - "TR3", - "TR4", - "TR5", - "TR6", - "TR7", - - "X0", - "X1", - "X2", - "X3", - "X4", - "X5", - "X6", - "X7", - - "NONE", /* [D_NONE] */ -}; - -int -Rconv(Fmt *fp) -{ - char str[STRINGSZ]; - int r; - - r = va_arg(fp->args, int); - if(r >= D_AL && r <= D_NONE) - sprint(str, "%s", regstr[r-D_AL]); - else - sprint(str, "gok(%d)", r); - - return fmtstrcpy(fp, str); -} - -int -Sconv(Fmt *fp) -{ - int i, c; - char str[STRINGSZ], *p, *a; - - a = va_arg(fp->args, char*); - p = str; - for(i=0; i= 'a' && c <= 'z' || - c >= 'A' && c <= 'Z' || - c >= '0' && c <= '9') { - *p++ = c; - continue; - } - *p++ = '\\'; - switch(c) { - default: - if(c < 040 || c >= 0177) - break; /* not portable */ - p[-1] = c; - continue; - case 0: - *p++ = 'z'; - continue; - case '\\': - case '"': - *p++ = c; - continue; - case '\n': - *p++ = 'n'; - continue; - case '\t': - *p++ = 't'; - continue; - } - *p++ = (c>>6) + '0'; - *p++ = ((c>>3) & 7) + '0'; - *p++ = (c & 7) + '0'; - } - *p = 0; - return fmtstrcpy(fp, str); -} - int Iconv(Fmt *fp) { @@ -352,27 +65,3 @@ Iconv(Fmt *fp) free(s); return 0; } - -void -diag(char *fmt, ...) -{ - char buf[1024], *tn, *sep; - va_list arg; - - 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%s\n", tn, sep, buf); - - nerrors++; - if(nerrors > 20) { - print("too many errors\n"); - errorexit(); - } -} diff --git a/src/cmd/8l/obj.c b/src/cmd/8l/obj.c index 3fdc41381..1b65c5eb9 100644 --- a/src/cmd/8l/obj.c +++ b/src/cmd/8l/obj.c @@ -30,7 +30,6 @@ // Reading object files. -#define EXTERN #include "l.h" #include "../ld/lib.h" #include "../ld/elf.h" @@ -39,110 +38,17 @@ #include "../ld/pe.h" #include -#ifndef DEFAULT -#define DEFAULT '9' -#endif - -char *noname = ""; -char *thestring = "386"; - -Header headers[] = { - "garbunix", Hgarbunix, - "unixcoff", Hunixcoff, - "plan9", Hplan9x32, - "msdoscom", Hmsdoscom, - "msdosexe", Hmsdosexe, - "darwin", Hdarwin, - "dragonfly", Hdragonfly, - "linux", Hlinux, - "freebsd", Hfreebsd, - "netbsd", Hnetbsd, - "openbsd", Hopenbsd, - "windows", Hwindows, - "windowsgui", Hwindows, - 0, 0 -}; - -/* - * -Hgarbunix -T0x40004C -D0x10000000 is garbage unix - * -Hunixcoff -T0xd0 -R4 is unix coff - * -Hplan9 -T4128 -R4096 is plan9 format - * -Hmsdoscom -Tx -Rx is MS-DOS .COM - * -Hmsdosexe -Tx -Rx is fake MS-DOS .EXE - * -Hdarwin -Tx -Rx is Apple Mach-O - * -Hdragonfly -Tx -Rx is DragonFly ELF32 - * -Hlinux -Tx -Rx is Linux ELF32 - * -Hfreebsd -Tx -Rx is FreeBSD ELF32 - * -Hnetbsd -Tx -Rx is NetBSD ELF32 - * -Hopenbsd -Tx -Rx is OpenBSD ELF32 - * -Hwindows -Tx -Rx is MS Windows PE32 - */ +char* thestring = "386"; +LinkArch* thelinkarch = &link386; void -main(int argc, char *argv[]) +linkarchinit(void) { - Binit(&bso, 1, OWRITE); - listinit(); - memset(debug, 0, sizeof(debug)); - nerrors = 0; - outfile = nil; - HEADTYPE = -1; - INITTEXT = -1; - INITDAT = -1; - INITRND = -1; - INITENTRY = 0; - linkmode = LinkAuto; - nuxiinit(); - - flagcount("1", "use alternate profiling code", &debug['1']); - flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo); - flagstr("E", "sym: entry symbol", &INITENTRY); - flagint32("D", "addr: data address", &INITDAT); - flagfn1("I", "interp: set ELF interp", setinterp); - flagfn1("L", "dir: add dir to library path", Lflag); - flagfn1("H", "head: header type", setheadtype); - flagcount("K", "add stack underflow checks", &debug['K']); - flagcount("O", "print pc-line tables", &debug['O']); - flagcount("Q", "debug byte-register code gen", &debug['Q']); - flagint32("R", "rnd: address rounding", &INITRND); - flagcount("S", "check type signatures", &debug['S']); - flagint32("T", "addr: text address", &INITTEXT); - flagfn0("V", "print version and exit", doversion); - flagcount("W", "disassemble input", &debug['W']); - flagfn2("X", "name value: define string data", addstrdata); - flagcount("Z", "clear stack frame on entry", &debug['Z']); - flagcount("a", "disassemble output", &debug['a']); - flagcount("c", "dump call graph", &debug['c']); - flagcount("d", "disable dynamic executable", &debug['d']); - flagstr("extld", "linker to run in external mode", &extld); - flagstr("extldflags", "flags for external linker", &extldflags); - flagcount("f", "ignore version mismatch", &debug['f']); - flagcount("g", "disable go package data checks", &debug['g']); - flagstr("installsuffix", "pkg directory suffix", &flag_installsuffix); - flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode); - flagstr("k", "sym: set field tracking symbol", &tracksym); - flagstr("o", "outfile: set output file", &outfile); - flagcount("p", "insert profiling code", &debug['p']); - flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath); - flagcount("race", "enable race detector", &flag_race); - flagcount("s", "disable symbol table", &debug['s']); - flagcount("n", "dump symbol table", &debug['n']); - flagstr("tmpdir", "leave temporary files in this directory", &tmpdir); - flagcount("u", "reject unsafe packages", &debug['u']); - flagcount("v", "print link trace", &debug['v']); - flagcount("w", "disable DWARF generation", &debug['w']); - // TODO: link mode flag - - flagparse(&argc, &argv, usage); - - if(argc != 1) - usage(); - - mywhatsys(); // get goos - - if(HEADTYPE == -1) - HEADTYPE = headtype(goos); +} +void +archinit(void) +{ // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when // Go was built; see ../../make.bash. if(linkmode == LinkAuto && strcmp(getgoextlinkenabled(), "0") == 0) @@ -164,40 +70,12 @@ main(int argc, char *argv[]) break; } - if(outfile == nil) { - if(HEADTYPE == Hwindows) - outfile = "8.out.exe"; - else - outfile = "8.out"; - } - - libinit(); - switch(HEADTYPE) { default: diag("unknown -H option"); errorexit(); - case Hgarbunix: /* this is garbage */ - HEADR = 20L+56L; - if(INITTEXT == -1) - INITTEXT = 0x40004CL; - if(INITDAT == -1) - INITDAT = 0x10000000L; - if(INITRND == -1) - INITRND = 0; - break; - case Hunixcoff: /* is unix coff */ - HEADR = 0xd0L; - if(INITTEXT == -1) - INITTEXT = 0xd0; - if(INITDAT == -1) - INITDAT = 0x400000; - if(INITRND == -1) - INITRND = 0; - break; - case Hplan9x32: /* plan 9 */ - tlsoffset = -8; + case Hplan9: /* plan 9 */ HEADR = 32L; if(INITTEXT == -1) INITTEXT = 4096+32; @@ -206,33 +84,7 @@ main(int argc, char *argv[]) if(INITRND == -1) INITRND = 4096; break; - case Hmsdoscom: /* MS-DOS .COM */ - HEADR = 0; - if(INITTEXT == -1) - INITTEXT = 0x0100; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = 4; - break; - case Hmsdosexe: /* fake MS-DOS .EXE */ - HEADR = 0x200; - if(INITTEXT == -1) - INITTEXT = 0x0100; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = 4; - HEADR += (INITTEXT & 0xFFFF); - if(debug['v']) - Bprint(&bso, "HEADR = 0x%d\n", HEADR); - break; case Hdarwin: /* apple MACH */ - /* - * OS X system constant - offset from %gs to our TLS. - * Explained in ../../pkg/runtime/cgo/gcc_darwin_386.c. - */ - tlsoffset = 0x468; machoinit(); HEADR = INITIAL_MACHO_HEADR; if(INITTEXT == -1) @@ -247,13 +99,6 @@ main(int argc, char *argv[]) case Hnetbsd: case Hopenbsd: case Hdragonfly: - /* - * ELF uses TLS offsets negative from %gs. - * Translate 0(GS) and 4(GS) into -8(GS) and -4(GS). - * Also known to ../../pkg/runtime/sys_linux_386.s - * and ../../pkg/runtime/cgo/gcc_linux_386.c. - */ - tlsoffset = -8; elfinit(); HEADR = ELFRESERVE; if(INITTEXT == -1) @@ -263,6 +108,19 @@ main(int argc, char *argv[]) if(INITRND == -1) INITRND = 4096; break; + + case Hnacl: + elfinit(); + HEADR = 0x10000; + funcalign = 32; + if(INITTEXT == -1) + INITTEXT = 0x20000; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 0x10000; + break; + case Hwindows: /* PE executable */ peinit(); HEADR = PEFILEHEADR; @@ -275,518 +133,6 @@ main(int argc, char *argv[]) break; } if(INITDAT != 0 && INITRND != 0) - print("warning: -D0x%ux is ignored because of -R0x%ux\n", + print("warning: -D0x%llux is ignored because of -R0x%ux\n", INITDAT, INITRND); - if(debug['v']) - Bprint(&bso, "HEADER = -H0x%d -T0x%ux -D0x%ux -R0x%ux\n", - HEADTYPE, INITTEXT, INITDAT, INITRND); - Bflush(&bso); - - instinit(); - zprg.link = P; - zprg.pcond = P; - zprg.back = 2; - zprg.as = AGOK; - zprg.from.type = D_NONE; - zprg.from.index = D_NONE; - zprg.from.scale = 1; - zprg.to = zprg.from; - - pcstr = "%.6ux "; - histgen = 0; - pc = 0; - dtype = 4; - version = 0; - cbp = buf.cbuf; - cbc = sizeof(buf.cbuf); - - addlibpath("command line", "command line", argv[0], "main"); - loadlib(); - deadcode(); - patch(); - follow(); - doelf(); - if(HEADTYPE == Hdarwin) - domacho(); - if(HEADTYPE == Hwindows) - dope(); - dostkoff(); - dostkcheck(); - if(debug['p']) - if(debug['1']) - doprof1(); - else - doprof2(); - span(); - addexport(); - textaddress(); - pclntab(); - symtab(); - dodata(); - address(); - doweak(); - reloc(); - asmb(); - undef(); - hostlink(); - - if(debug['v']) { - Bprint(&bso, "%5.2f cpu time\n", cputime()); - Bprint(&bso, "%d symbols\n", nsymbol); - Bprint(&bso, "%d sizeof adr\n", sizeof(Adr)); - Bprint(&bso, "%d sizeof prog\n", sizeof(Prog)); - } - Bflush(&bso); - - errorexit(); -} - -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; - Sym *s; - Auto *u; - - t = BGETC(f); - a->index = D_NONE; - a->scale = 0; - if(t & T_INDEX) { - a->index = BGETC(f); - a->scale = BGETC(f); - } - a->type = D_NONE; - a->offset = 0; - if(t & T_OFFSET) - a->offset = BGETLE4(f); - a->offset2 = 0; - if(t & T_OFFSET2) { - a->offset2 = BGETLE4(f); - a->type = D_CONST2; - } - a->sym = S; - if(t & T_SYM) - a->sym = zsym(pn, f, h); - if(t & T_FCONST) { - a->ieee.l = BGETLE4(f); - a->ieee.h = BGETLE4(f); - a->type = D_FCONST; - } else - if(t & T_SCONST) { - Bread(f, a->scon, NSNAME); - a->type = D_SCONST; - } - if(t & T_TYPE) - a->type = BGETC(f); - adrgotype = S; - if(t & T_GOTYPE) - adrgotype = zsym(pn, f, h); - - t = a->type; - if(t == D_INDIR+D_GS) - a->offset += tlsoffset; - - s = a->sym; - if(s == S) - return; - if(t != D_AUTO && t != D_PARAM) { - if(adrgotype) - s->gotype = adrgotype; - return; - } - l = a->offset; - for(u=curauto; u; u=u->link) { - if(u->asym == s) - if(u->type == t) { - if(u->aoffset > l) - u->aoffset = l; - if(adrgotype) - u->gotype = adrgotype; - return; - } - } - - u = mal(sizeof(*u)); - u->link = curauto; - curauto = u; - u->asym = s; - u->aoffset = l; - u->type = t; - u->gotype = adrgotype; -} - -void -nopout(Prog *p) -{ - p->as = ANOP; - p->from.type = D_NONE; - p->to.type = D_NONE; -} - -void -ldobj1(Biobuf *f, char *pkg, int64 len, char *pn) -{ - int32 ipc; - Prog *p; - int v, o, r, skip; - Sym *h[NSYM], *s; - uint32 sig; - int ntext; - int32 eof; - char *name, *x; - char src[1024]; - Prog *lastp; - - lastp = nil; - ntext = 0; - eof = Boffset(f) + len; - src[0] = 0; - pn = estrdup(pn); // we keep it in Sym* references - -newloop: - memset(h, 0, sizeof(h)); - version++; - histfrogp = 0; - ipc = pc; - skip = 0; - -loop: - if(f->state == Bracteof || Boffset(f) >= eof) - goto eof; - o = BGETC(f); - if(o == Beof) - goto eof; - o |= BGETC(f) << 8; - if(o <= AXXX || o >= ALAST) { - if(o < 0) - goto eof; - diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o); - print(" probably not a .%c file\n", thechar); - errorexit(); - } - - if(o == ANAME || o == ASIGNAME) { - sig = 0; - if(o == ASIGNAME) - sig = BGETLE4(f); - v = BGETC(f); /* type */ - o = BGETC(f); /* sym */ - r = 0; - if(v == D_STATIC) - r = version; - name = Brdline(f, '\0'); - if(name == nil) { - if(Blinelen(f) > 0) { - fprint(2, "%s: name too long\n", pn); - errorexit(); - } - goto eof; - } - x = expandpkg(name, pkg); - s = lookup(x, r); - if(x != name) - free(x); - - if(debug['S'] && r == 0) - sig = 1729; - if(sig != 0){ - if(s->sig != 0 && s->sig != sig) - 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)) - mangle(pn); - h[o] = s; - if((v == D_EXTERN || v == D_STATIC) && s->type == 0) - s->type = SXREF; - if(v == D_FILE) { - if(s->type != SFILE) { - histgen++; - s->type = SFILE; - s->value = histgen; - } - if(histfrogp < MAXHIST) { - histfrog[histfrogp] = s; - histfrogp++; - } else - collapsefrog(s); - dwarfaddfrag(s->value, s->name); - } - goto loop; - } - - p = mal(sizeof(*p)); - p->as = o; - p->line = BGETLE4(f); - p->back = 2; - zaddr(pn, f, &p->from, h); - fromgotype = adrgotype; - zaddr(pn, f, &p->to, h); - - if(debug['W']) - print("%P\n", p); - - switch(p->as) { - case AHISTORY: - if(p->to.offset == -1) { - addlib(src, pn); - histfrogp = 0; - goto loop; - } - if(src[0] == '\0') - copyhistfrog(src, sizeof src); - addhist(p->line, D_FILE); /* 'z' */ - if(p->to.offset) - addhist(p->to.offset, D_FILE1); /* 'Z' */ - savehist(p->line, p->to.offset); - histfrogp = 0; - goto loop; - - case AEND: - histtoauto(); - if(cursym != nil && cursym->text) - cursym->autom = curauto; - curauto = 0; - cursym = nil; - if(Boffset(f) == eof) - return; - goto newloop; - - case AGLOBL: - s = p->from.sym; - if(s->type == 0 || s->type == SXREF) { - s->type = SBSS; - s->size = 0; - } - if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) { - diag("%s: redefinition: %s in %s", - pn, s->name, TNAME); - s->type = SBSS; - s->size = 0; - } - 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; - else if(p->from.scale & NOPTR) - s->type = SNOPTRBSS; - goto loop; - - 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->dupok) { -// if(debug['v']) -// Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn); - goto loop; - } - 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(); - } - savedata(s, p, pn); - unmal(p, sizeof *p); - goto loop; - - case AGOK: - diag("%s: GOK opcode in %s", pn, TNAME); - pc++; - goto loop; - - case ATYPE: - if(skip) - goto casdef; - pc++; - goto loop; - - case ATEXT: - s = p->from.sym; - if(s->text != nil) { - if(p->from.scale & DUPOK) { - skip = 1; - goto casdef; - } - 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']) - diag("skipping: %s: redefinition: %s", pn, s->name); - return; - } - if(cursym != nil && cursym->text) { - histtoauto(); - cursym->autom = curauto; - curauto = 0; - } - skip = 0; - 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; - goto casdef; - } - diag("%s: redefinition: %s\n%P", pn, s->name, p); - } - s->type = STEXT; - s->hist = gethist(); - s->value = pc; - s->args = p->to.offset2; - lastp = p; - p->pc = pc++; - goto loop; - - case AFMOVF: - case AFADDF: - case AFSUBF: - case AFSUBRF: - case AFMULF: - case AFDIVF: - case AFDIVRF: - case AFCOMF: - case AFCOMFP: - case AMOVSS: - case AADDSS: - case ASUBSS: - case AMULSS: - case ADIVSS: - case ACOMISS: - case AUCOMISS: - if(skip) - goto casdef; - if(p->from.type == D_FCONST) { - /* size sb 9 max */ - sprint(literal, "$%ux", ieeedtof(&p->from.ieee)); - s = lookup(literal, 0); - if(s->type == 0) { - s->type = SRODATA; - adduint32(s, ieeedtof(&p->from.ieee)); - s->reachable = 0; - } - p->from.type = D_EXTERN; - p->from.sym = s; - p->from.offset = 0; - } - goto casdef; - - case AFMOVD: - case AFADDD: - case AFSUBD: - case AFSUBRD: - case AFMULD: - case AFDIVD: - case AFDIVRD: - case AFCOMD: - case AFCOMDP: - case AMOVSD: - case AADDSD: - case ASUBSD: - case AMULSD: - case ADIVSD: - case ACOMISD: - case AUCOMISD: - if(skip) - goto casdef; - if(p->from.type == D_FCONST) { - /* size sb 18 max */ - sprint(literal, "$%ux.%ux", - p->from.ieee.l, p->from.ieee.h); - s = lookup(literal, 0); - if(s->type == 0) { - s->type = SRODATA; - adduint32(s, p->from.ieee.l); - adduint32(s, p->from.ieee.h); - s->reachable = 0; - } - p->from.type = D_EXTERN; - p->from.sym = s; - p->from.offset = 0; - } - goto casdef; - - casdef: - 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; - goto loop; - } - -eof: - diag("truncated object file: %s", pn); -} - -Prog* -prg(void) -{ - Prog *p; - - p = mal(sizeof(Prog)); - *p = zprg; - return p; -} - -Prog* -copyp(Prog *q) -{ - Prog *p; - - p = prg(); - *p = *q; - return p; -} - -Prog* -appendp(Prog *q) -{ - Prog *p; - - p = prg(); - p->link = q->link; - q->link = p; - p->line = q->line; - return p; } diff --git a/src/cmd/8l/optab.c b/src/cmd/8l/optab.c deleted file mode 100644 index a4c40e8e3..000000000 --- a/src/cmd/8l/optab.c +++ /dev/null @@ -1,1030 +0,0 @@ -// Inferno utils/8l/optab.c -// http://code.google.com/p/inferno-os/source/browse/utils/8l/optab.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 "l.h" - -uchar ynone[] = -{ - Ynone, Ynone, Zlit, 1, - 0 -}; -uchar ytext[] = -{ - Ymb, Yi32, Zpseudo,1, - 0 -}; -uchar ynop[] = -{ - Ynone, Ynone, Zpseudo,1, - Ynone, Yml, Zpseudo,1, - Ynone, Yrf, Zpseudo,1, - Yml, Ynone, Zpseudo,1, - Yrf, Ynone, Zpseudo,1, - 0 -}; -uchar yfuncdata[] = -{ - Yi32, Ym, Zpseudo, 0, - 0 -}; -uchar ypcdata[] = -{ - Yi32, Yi32, Zpseudo, 0, - 0, -}; -uchar yxorb[] = -{ - Yi32, Yal, Zib_, 1, - Yi32, Ymb, Zibo_m, 2, - Yrb, Ymb, Zr_m, 1, - Ymb, Yrb, Zm_r, 1, - 0 -}; -uchar yxorl[] = -{ - Yi8, Yml, Zibo_m, 2, - Yi32, Yax, Zil_, 1, - Yi32, Yml, Zilo_m, 2, - Yrl, Yml, Zr_m, 1, - Yml, Yrl, Zm_r, 1, - 0 -}; -uchar yaddl[] = -{ - Yi8, Yml, Zibo_m, 2, - Yi32, Yax, Zil_, 1, - Yi32, Yml, Zilo_m, 2, - Yrl, Yml, Zr_m, 1, - Yml, Yrl, Zm_r, 1, - 0 -}; -uchar yincb[] = -{ - Ynone, Ymb, Zo_m, 2, - 0 -}; -uchar yincl[] = -{ - Ynone, Yrl, Z_rp, 1, - Ynone, Yml, Zo_m, 2, - 0 -}; -uchar ycmpb[] = -{ - Yal, Yi32, Z_ib, 1, - Ymb, Yi32, Zm_ibo, 2, - Ymb, Yrb, Zm_r, 1, - Yrb, Ymb, Zr_m, 1, - 0 -}; -uchar ycmpl[] = -{ - Yml, Yi8, Zm_ibo, 2, - Yax, Yi32, Z_il, 1, - Yml, Yi32, Zm_ilo, 2, - Yml, Yrl, Zm_r, 1, - Yrl, Yml, Zr_m, 1, - 0 -}; -uchar yshb[] = -{ - Yi1, Ymb, Zo_m, 2, - Yi32, Ymb, Zibo_m, 2, - Ycx, Ymb, Zo_m, 2, - 0 -}; -uchar yshl[] = -{ - Yi1, Yml, Zo_m, 2, - Yi32, Yml, Zibo_m, 2, - Ycl, Yml, Zo_m, 2, - Ycx, Yml, Zo_m, 2, - 0 -}; -uchar ytestb[] = -{ - Yi32, Yal, Zib_, 1, - Yi32, Ymb, Zibo_m, 2, - Yrb, Ymb, Zr_m, 1, - Ymb, Yrb, Zm_r, 1, - 0 -}; -uchar ytestl[] = -{ - Yi32, Yax, Zil_, 1, - Yi32, Yml, Zilo_m, 2, - Yrl, Yml, Zr_m, 1, - Yml, Yrl, Zm_r, 1, - 0 -}; -uchar ymovb[] = -{ - Yrb, Ymb, Zr_m, 1, - Ymb, Yrb, Zm_r, 1, - Yi32, Yrb, Zib_rp, 1, - Yi32, Ymb, Zibo_m, 2, - 0 -}; -uchar ymovw[] = -{ - Yrl, Yml, Zr_m, 1, - Yml, Yrl, Zm_r, 1, - Yi0, Yrl, Zclr, 1+2, -// Yi0, Yml, Zibo_m, 2, // shorter but slower AND $0,dst - Yi32, Yrl, Zil_rp, 1, - Yi32, Yml, Zilo_m, 2, - Yiauto, Yrl, Zaut_r, 1, - 0 -}; -uchar ymovl[] = -{ - Yrl, Yml, Zr_m, 1, - Yml, Yrl, Zm_r, 1, - Yi0, Yrl, Zclr, 1+2, -// Yi0, Yml, Zibo_m, 2, // shorter but slower AND $0,dst - Yi32, Yrl, Zil_rp, 1, - Yi32, Yml, Zilo_m, 2, - Yml, Yxr, Zm_r_xm, 2, // XMM MOVD (32 bit) - Yxr, Yml, Zr_m_xm, 2, // XMM MOVD (32 bit) - Yiauto, Yrl, Zaut_r, 1, - 0 -}; -uchar ymovq[] = -{ - Yml, Yxr, Zm_r_xm, 2, - 0 -}; -uchar ym_rl[] = -{ - Ym, Yrl, Zm_r, 1, - 0 -}; -uchar yrl_m[] = -{ - Yrl, Ym, Zr_m, 1, - 0 -}; -uchar ymb_rl[] = -{ - Ymb, Yrl, Zm_r, 1, - 0 -}; -uchar yml_rl[] = -{ - Yml, Yrl, Zm_r, 1, - 0 -}; -uchar yrb_mb[] = -{ - Yrb, Ymb, Zr_m, 1, - 0 -}; -uchar yrl_ml[] = -{ - Yrl, Yml, Zr_m, 1, - 0 -}; -uchar yml_mb[] = -{ - Yrb, Ymb, Zr_m, 1, - Ymb, Yrb, Zm_r, 1, - 0 -}; -uchar yxchg[] = -{ - Yax, Yrl, Z_rp, 1, - Yrl, Yax, Zrp_, 1, - Yrl, Yml, Zr_m, 1, - Yml, Yrl, Zm_r, 1, - 0 -}; -uchar ydivl[] = -{ - Yml, Ynone, Zm_o, 2, - 0 -}; -uchar ydivb[] = -{ - Ymb, Ynone, Zm_o, 2, - 0 -}; -uchar yimul[] = -{ - Yml, Ynone, Zm_o, 2, - Yi8, Yrl, Zib_rr, 1, - Yi32, Yrl, Zil_rr, 1, - 0 -}; -uchar ybyte[] = -{ - Yi32, Ynone, Zbyte, 1, - 0 -}; -uchar yin[] = -{ - Yi32, Ynone, Zib_, 1, - Ynone, Ynone, Zlit, 1, - 0 -}; -uchar yint[] = -{ - Yi32, Ynone, Zib_, 1, - 0 -}; -uchar ypushl[] = -{ - Yrl, Ynone, Zrp_, 1, - Ym, Ynone, Zm_o, 2, - Yi8, Ynone, Zib_, 1, - Yi32, Ynone, Zil_, 1, - 0 -}; -uchar ypopl[] = -{ - Ynone, Yrl, Z_rp, 1, - Ynone, Ym, Zo_m, 2, - 0 -}; -uchar ybswap[] = -{ - Ynone, Yrl, Z_rp, 1, - 0, -}; -uchar yscond[] = -{ - Ynone, Ymb, Zo_m, 2, - 0 -}; -uchar yjcond[] = -{ - Ynone, Ybr, Zbr, 0, - Yi0, Ybr, Zbr, 0, - Yi1, Ybr, Zbr, 1, - 0 -}; -uchar yloop[] = -{ - Ynone, Ybr, Zloop, 1, - 0 -}; -uchar ycall[] = -{ - Ynone, Yml, Zo_m, 0, - Yrx, Yrx, Zo_m, 2, - Ynone, Ycol, Zcallind, 2, - Ynone, Ybr, Zcall, 0, - Ynone, Yi32, Zcallcon, 1, - 0 -}; -uchar yjmp[] = -{ - Ynone, Yml, Zo_m, 2, - Ynone, Ybr, Zjmp, 0, - Ynone, Yi32, Zjmpcon, 1, - 0 -}; - -uchar yfmvd[] = -{ - Ym, Yf0, Zm_o, 2, - Yf0, Ym, Zo_m, 2, - Yrf, Yf0, Zm_o, 2, - Yf0, Yrf, Zo_m, 2, - 0 -}; -uchar yfmvdp[] = -{ - Yf0, Ym, Zo_m, 2, - Yf0, Yrf, Zo_m, 2, - 0 -}; -uchar yfmvf[] = -{ - Ym, Yf0, Zm_o, 2, - Yf0, Ym, Zo_m, 2, - 0 -}; -uchar yfmvx[] = -{ - Ym, Yf0, Zm_o, 2, - 0 -}; -uchar yfmvp[] = -{ - Yf0, Ym, Zo_m, 2, - 0 -}; -uchar yfcmv[] = -{ - Yrf, Yf0, Zm_o, 2, - 0 -}; -uchar yfadd[] = -{ - Ym, Yf0, Zm_o, 2, - Yrf, Yf0, Zm_o, 2, - Yf0, Yrf, Zo_m, 2, - 0 -}; -uchar yfaddp[] = -{ - Yf0, Yrf, Zo_m, 2, - 0 -}; -uchar yfxch[] = -{ - Yf0, Yrf, Zo_m, 2, - Yrf, Yf0, Zm_o, 2, - 0 -}; -uchar ycompp[] = -{ - Yf0, Yrf, Zo_m, 2, /* botch is really f0,f1 */ - 0 -}; -uchar ystsw[] = -{ - Ynone, Ym, Zo_m, 2, - Ynone, Yax, Zlit, 1, - 0 -}; -uchar ystcw[] = -{ - Ynone, Ym, Zo_m, 2, - Ym, Ynone, Zm_o, 2, - 0 -}; -uchar ysvrs[] = -{ - Ynone, Ym, Zo_m, 2, - Ym, Ynone, Zm_o, 2, - 0 -}; -uchar ymskb[] = -{ - Yxr, Yrl, Zm_r_xm, 2, - Ymr, Yrl, Zm_r_xm, 1, - 0 -}; -uchar yxm[] = -{ - Yxm, Yxr, Zm_r_xm, 1, - 0 -}; -uchar yxcvm1[] = -{ - Yxm, Yxr, Zm_r_xm, 2, - Yxm, Ymr, Zm_r_xm, 2, - 0 -}; -uchar yxcvm2[] = -{ - Yxm, Yxr, Zm_r_xm, 2, - Ymm, Yxr, Zm_r_xm, 2, - 0 -}; -uchar yxmq[] = -{ - Yxm, Yxr, Zm_r_xm, 2, - 0 -}; -uchar yxr[] = -{ - Yxr, Yxr, Zm_r_xm, 1, - 0 -}; -uchar yxr_ml[] = -{ - Yxr, Yml, Zr_m_xm, 1, - 0 -}; -uchar yxcmp[] = -{ - Yxm, Yxr, Zm_r_xm, 1, - 0 -}; -uchar yxcmpi[] = -{ - Yxm, Yxr, Zm_r_i_xm, 2, - 0 -}; -uchar yxmov[] = -{ - Yxm, Yxr, Zm_r_xm, 1, - Yxr, Yxm, Zr_m_xm, 1, - 0 -}; -uchar yxcvfl[] = -{ - Yxm, Yrl, Zm_r_xm, 1, - 0 -}; -uchar yxcvlf[] = -{ - Yml, Yxr, Zm_r_xm, 1, - 0 -}; -uchar yxcvfq[] = -{ - Yxm, Yrl, Zm_r_xm, 2, - 0 -}; -uchar yxcvqf[] = -{ - Yml, Yxr, Zm_r_xm, 2, - 0 -}; -uchar yxrrl[] = -{ - Yxr, Yrl, Zm_r, 1, - 0 -}; -uchar yprefetch[] = -{ - Ym, Ynone, Zm_o, 2, - 0, -}; -uchar yaes[] = -{ - Yxm, Yxr, Zlitm_r, 2, - 0 -}; -uchar yinsrd[] = -{ - Yml, Yxr, Zibm_r, 2, - 0 -}; -uchar ymshufb[] = -{ - Yxm, Yxr, Zm2_r, 2, - 0 -}; - -Optab optab[] = -/* as, ytab, andproto, opcode */ -{ - { AXXX }, - { AAAA, ynone, Px, 0x37 }, - { AAAD, ynone, Px, 0xd5,0x0a }, - { AAAM, ynone, Px, 0xd4,0x0a }, - { AAAS, ynone, Px, 0x3f }, - { AADCB, yxorb, Pb, 0x14,0x80,(02),0x10,0x10 }, - { AADCL, yxorl, Px, 0x83,(02),0x15,0x81,(02),0x11,0x13 }, - { AADCW, yxorl, Pe, 0x83,(02),0x15,0x81,(02),0x11,0x13 }, - { AADDB, yxorb, Px, 0x04,0x80,(00),0x00,0x02 }, - { AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 }, - { AADDW, yaddl, Pe, 0x83,(00),0x05,0x81,(00),0x01,0x03 }, - { AADJSP }, - { AANDB, yxorb, Pb, 0x24,0x80,(04),0x20,0x22 }, - { AANDL, yxorl, Px, 0x83,(04),0x25,0x81,(04),0x21,0x23 }, - { AANDW, yxorl, Pe, 0x83,(04),0x25,0x81,(04),0x21,0x23 }, - { AARPL, yrl_ml, Px, 0x63 }, - { ABOUNDL, yrl_m, Px, 0x62 }, - { ABOUNDW, yrl_m, Pe, 0x62 }, - { ABSFL, yml_rl, Pm, 0xbc }, - { ABSFW, yml_rl, Pq, 0xbc }, - { ABSRL, yml_rl, Pm, 0xbd }, - { ABSRW, yml_rl, Pq, 0xbd }, - { ABTL, yml_rl, Pm, 0xa3 }, - { ABTW, yml_rl, Pq, 0xa3 }, - { ABTCL, yml_rl, Pm, 0xbb }, - { ABTCW, yml_rl, Pq, 0xbb }, - { ABTRL, yml_rl, Pm, 0xb3 }, - { ABTRW, yml_rl, Pq, 0xb3 }, - { ABTSL, yml_rl, Pm, 0xab }, - { ABTSW, yml_rl, Pq, 0xab }, - { ABYTE, ybyte, Px, 1 }, - { ACALL, ycall, Px, 0xff,(02),0xff,(0x15),0xe8 }, - { ACLC, ynone, Px, 0xf8 }, - { ACLD, ynone, Px, 0xfc }, - { ACLI, ynone, Px, 0xfa }, - { ACLTS, ynone, Pm, 0x06 }, - { ACMC, ynone, Px, 0xf5 }, - { ACMPB, ycmpb, Pb, 0x3c,0x80,(07),0x38,0x3a }, - { ACMPL, ycmpl, Px, 0x83,(07),0x3d,0x81,(07),0x39,0x3b }, - { ACMPW, ycmpl, Pe, 0x83,(07),0x3d,0x81,(07),0x39,0x3b }, - { ACMPSB, ynone, Pb, 0xa6 }, - { ACMPSL, ynone, Px, 0xa7 }, - { ACMPSW, ynone, Pe, 0xa7 }, - { ADAA, ynone, Px, 0x27 }, - { ADAS, ynone, Px, 0x2f }, - { ADATA }, - { ADECB, yincb, Pb, 0xfe,(01) }, - { ADECL, yincl, Px, 0x48,0xff,(01) }, - { ADECW, yincl, Pe, 0x48,0xff,(01) }, - { ADIVB, ydivb, Pb, 0xf6,(06) }, - { ADIVL, ydivl, Px, 0xf7,(06) }, - { ADIVW, ydivl, Pe, 0xf7,(06) }, - { AENTER }, /* botch */ - { AGLOBL }, - { AGOK }, - { AHISTORY }, - { AHLT, ynone, Px, 0xf4 }, - { AIDIVB, ydivb, Pb, 0xf6,(07) }, - { AIDIVL, ydivl, Px, 0xf7,(07) }, - { AIDIVW, ydivl, Pe, 0xf7,(07) }, - { AIMULB, ydivb, Pb, 0xf6,(05) }, - { AIMULL, yimul, Px, 0xf7,(05),0x6b,0x69 }, - { AIMULW, yimul, Pe, 0xf7,(05),0x6b,0x69 }, - { AINB, yin, Pb, 0xe4,0xec }, - { AINL, yin, Px, 0xe5,0xed }, - { AINW, yin, Pe, 0xe5,0xed }, - { AINCB, yincb, Pb, 0xfe,(00) }, - { AINCL, yincl, Px, 0x40,0xff,(00) }, - { AINCW, yincl, Pe, 0x40,0xff,(00) }, - { AINSB, ynone, Pb, 0x6c }, - { AINSL, ynone, Px, 0x6d }, - { AINSW, ynone, Pe, 0x6d }, - { AINT, yint, Px, 0xcd }, - { AINTO, ynone, Px, 0xce }, - { AIRETL, ynone, Px, 0xcf }, - { AIRETW, ynone, Pe, 0xcf }, - { AJCC, yjcond, Px, 0x73,0x83,(00) }, - { AJCS, yjcond, Px, 0x72,0x82 }, - { AJCXZL, yloop, Px, 0xe3 }, - { AJCXZW, yloop, Px, 0xe3 }, - { AJEQ, yjcond, Px, 0x74,0x84 }, - { AJGE, yjcond, Px, 0x7d,0x8d }, - { AJGT, yjcond, Px, 0x7f,0x8f }, - { AJHI, yjcond, Px, 0x77,0x87 }, - { AJLE, yjcond, Px, 0x7e,0x8e }, - { AJLS, yjcond, Px, 0x76,0x86 }, - { AJLT, yjcond, Px, 0x7c,0x8c }, - { AJMI, yjcond, Px, 0x78,0x88 }, - { AJMP, yjmp, Px, 0xff,(04),0xeb,0xe9 }, - { AJNE, yjcond, Px, 0x75,0x85 }, - { AJOC, yjcond, Px, 0x71,0x81,(00) }, - { AJOS, yjcond, Px, 0x70,0x80,(00) }, - { AJPC, yjcond, Px, 0x7b,0x8b }, - { AJPL, yjcond, Px, 0x79,0x89 }, - { AJPS, yjcond, Px, 0x7a,0x8a }, - { ALAHF, ynone, Px, 0x9f }, - { ALARL, yml_rl, Pm, 0x02 }, - { ALARW, yml_rl, Pq, 0x02 }, - { ALEAL, ym_rl, Px, 0x8d }, - { ALEAW, ym_rl, Pe, 0x8d }, - { ALEAVEL, ynone, Px, 0xc9 }, - { ALEAVEW, ynone, Pe, 0xc9 }, - { ALOCK, ynone, Px, 0xf0 }, - { ALODSB, ynone, Pb, 0xac }, - { ALODSL, ynone, Px, 0xad }, - { ALODSW, ynone, Pe, 0xad }, - { ALONG, ybyte, Px, 4 }, - { ALOOP, yloop, Px, 0xe2 }, - { ALOOPEQ, yloop, Px, 0xe1 }, - { ALOOPNE, yloop, Px, 0xe0 }, - { ALSLL, yml_rl, Pm, 0x03 }, - { ALSLW, yml_rl, Pq, 0x03 }, - { AMOVB, ymovb, Pb, 0x88,0x8a,0xb0,0xc6,(00) }, - { AMOVL, ymovl, Px, 0x89,0x8b,0x31,0x83,(04),0xb8,0xc7,(00),Pe,0x6e,Pe,0x7e,0 }, - { AMOVW, ymovw, Pe, 0x89,0x8b,0x31,0x83,(04),0xb8,0xc7,(00),0 }, - { AMOVQ, ymovq, Pf3, 0x7e }, - { AMOVBLSX, ymb_rl, Pm, 0xbe }, - { AMOVBLZX, ymb_rl, Pm, 0xb6 }, - { AMOVBWSX, ymb_rl, Pq, 0xbe }, - { AMOVBWZX, ymb_rl, Pq, 0xb6 }, - { AMOVWLSX, yml_rl, Pm, 0xbf }, - { AMOVWLZX, yml_rl, Pm, 0xb7 }, - { AMOVSB, ynone, Pb, 0xa4 }, - { AMOVSL, ynone, Px, 0xa5 }, - { AMOVSW, ynone, Pe, 0xa5 }, - { AMULB, ydivb, Pb, 0xf6,(04) }, - { AMULL, ydivl, Px, 0xf7,(04) }, - { AMULW, ydivl, Pe, 0xf7,(04) }, - { ANAME }, - { ANEGB, yscond, Px, 0xf6,(03) }, - { ANEGL, yscond, Px, 0xf7,(03) }, - { ANEGW, yscond, Pe, 0xf7,(03) }, - { ANOP, ynop, Px,0,0 }, - { ANOTB, yscond, Px, 0xf6,(02) }, - { ANOTL, yscond, Px, 0xf7,(02) }, - { ANOTW, yscond, Pe, 0xf7,(02) }, - { AORB, yxorb, Pb, 0x0c,0x80,(01),0x08,0x0a }, - { AORL, yxorl, Px, 0x83,(01),0x0d,0x81,(01),0x09,0x0b }, - { AORW, yxorl, Pe, 0x83,(01),0x0d,0x81,(01),0x09,0x0b }, - { AOUTB, yin, Pb, 0xe6,0xee }, - { AOUTL, yin, Px, 0xe7,0xef }, - { AOUTW, yin, Pe, 0xe7,0xef }, - { AOUTSB, ynone, Pb, 0x6e }, - { AOUTSL, ynone, Px, 0x6f }, - { AOUTSW, ynone, Pe, 0x6f }, - { APAUSE, ynone, Px, 0xf3,0x90 }, - { APOPAL, ynone, Px, 0x61 }, - { APOPAW, ynone, Pe, 0x61 }, - { APOPFL, ynone, Px, 0x9d }, - { APOPFW, ynone, Pe, 0x9d }, - { APOPL, ypopl, Px, 0x58,0x8f,(00) }, - { APOPW, ypopl, Pe, 0x58,0x8f,(00) }, - { APUSHAL, ynone, Px, 0x60 }, - { APUSHAW, ynone, Pe, 0x60 }, - { APUSHFL, ynone, Px, 0x9c }, - { APUSHFW, ynone, Pe, 0x9c }, - { APUSHL, ypushl, Px, 0x50,0xff,(06),0x6a,0x68 }, - { APUSHW, ypushl, Pe, 0x50,0xff,(06),0x6a,0x68 }, - { ARCLB, yshb, Pb, 0xd0,(02),0xc0,(02),0xd2,(02) }, - { ARCLL, yshl, Px, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) }, - { ARCLW, yshl, Pe, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) }, - { ARCRB, yshb, Pb, 0xd0,(03),0xc0,(03),0xd2,(03) }, - { ARCRL, yshl, Px, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) }, - { ARCRW, yshl, Pe, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) }, - { AREP, ynone, Px, 0xf3 }, - { AREPN, ynone, Px, 0xf2 }, - { ARET, ynone, Px, 0xc3 }, - { AROLB, yshb, Pb, 0xd0,(00),0xc0,(00),0xd2,(00) }, - { AROLL, yshl, Px, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) }, - { AROLW, yshl, Pe, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) }, - { ARORB, yshb, Pb, 0xd0,(01),0xc0,(01),0xd2,(01) }, - { ARORL, yshl, Px, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) }, - { ARORW, yshl, Pe, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) }, - { ASAHF, ynone, Px, 0x9e }, - { ASALB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) }, - { ASALL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, - { ASALW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, - { ASARB, yshb, Pb, 0xd0,(07),0xc0,(07),0xd2,(07) }, - { ASARL, yshl, Px, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) }, - { ASARW, yshl, Pe, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) }, - { ASBBB, yxorb, Pb, 0x1c,0x80,(03),0x18,0x1a }, - { ASBBL, yxorl, Px, 0x83,(03),0x1d,0x81,(03),0x19,0x1b }, - { ASBBW, yxorl, Pe, 0x83,(03),0x1d,0x81,(03),0x19,0x1b }, - { ASCASB, ynone, Pb, 0xae }, - { ASCASL, ynone, Px, 0xaf }, - { ASCASW, ynone, Pe, 0xaf }, - { ASETCC, yscond, Pm, 0x93,(00) }, - { ASETCS, yscond, Pm, 0x92,(00) }, - { ASETEQ, yscond, Pm, 0x94,(00) }, - { ASETGE, yscond, Pm, 0x9d,(00) }, - { ASETGT, yscond, Pm, 0x9f,(00) }, - { ASETHI, yscond, Pm, 0x97,(00) }, - { ASETLE, yscond, Pm, 0x9e,(00) }, - { ASETLS, yscond, Pm, 0x96,(00) }, - { ASETLT, yscond, Pm, 0x9c,(00) }, - { ASETMI, yscond, Pm, 0x98,(00) }, - { ASETNE, yscond, Pm, 0x95,(00) }, - { ASETOC, yscond, Pm, 0x91,(00) }, - { ASETOS, yscond, Pm, 0x90,(00) }, - { ASETPC, yscond, Pm, 0x96,(00) }, - { ASETPL, yscond, Pm, 0x99,(00) }, - { ASETPS, yscond, Pm, 0x9a,(00) }, - { ACDQ, ynone, Px, 0x99 }, - { ACWD, ynone, Pe, 0x99 }, - { ASHLB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) }, - { ASHLL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, - { ASHLW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) }, - { ASHRB, yshb, Pb, 0xd0,(05),0xc0,(05),0xd2,(05) }, - { ASHRL, yshl, Px, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) }, - { ASHRW, yshl, Pe, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) }, - { ASTC, ynone, Px, 0xf9 }, - { ASTD, ynone, Px, 0xfd }, - { ASTI, ynone, Px, 0xfb }, - { ASTOSB, ynone, Pb, 0xaa }, - { ASTOSL, ynone, Px, 0xab }, - { ASTOSW, ynone, Pe, 0xab }, - { ASUBB, yxorb, Pb, 0x2c,0x80,(05),0x28,0x2a }, - { ASUBL, yaddl, Px, 0x83,(05),0x2d,0x81,(05),0x29,0x2b }, - { ASUBW, yaddl, Pe, 0x83,(05),0x2d,0x81,(05),0x29,0x2b }, - { ASYSCALL, ynone, Px, 0xcd,100 }, - { ATESTB, ytestb, Pb, 0xa8,0xf6,(00),0x84,0x84 }, - { ATESTL, ytestl, Px, 0xa9,0xf7,(00),0x85,0x85 }, - { ATESTW, ytestl, Pe, 0xa9,0xf7,(00),0x85,0x85 }, - { ATEXT, ytext, Px }, - { AVERR, ydivl, Pm, 0x00,(04) }, - { AVERW, ydivl, Pm, 0x00,(05) }, - { AWAIT, ynone, Px, 0x9b }, - { AWORD, ybyte, Px, 2 }, - { AXCHGB, yml_mb, Pb, 0x86,0x86 }, - { AXCHGL, yxchg, Px, 0x90,0x90,0x87,0x87 }, - { AXCHGW, yxchg, Pe, 0x90,0x90,0x87,0x87 }, - { AXLAT, ynone, Px, 0xd7 }, - { AXORB, yxorb, Pb, 0x34,0x80,(06),0x30,0x32 }, - { AXORL, yxorl, Px, 0x83,(06),0x35,0x81,(06),0x31,0x33 }, - { AXORW, yxorl, Pe, 0x83,(06),0x35,0x81,(06),0x31,0x33 }, - - { AFMOVB, yfmvx, Px, 0xdf,(04) }, - { AFMOVBP, yfmvp, Px, 0xdf,(06) }, - { AFMOVD, yfmvd, Px, 0xdd,(00),0xdd,(02),0xd9,(00),0xdd,(02) }, - { AFMOVDP, yfmvdp, Px, 0xdd,(03),0xdd,(03) }, - { AFMOVF, yfmvf, Px, 0xd9,(00),0xd9,(02) }, - { AFMOVFP, yfmvp, Px, 0xd9,(03) }, - { AFMOVL, yfmvf, Px, 0xdb,(00),0xdb,(02) }, - { AFMOVLP, yfmvp, Px, 0xdb,(03) }, - { AFMOVV, yfmvx, Px, 0xdf,(05) }, - { AFMOVVP, yfmvp, Px, 0xdf,(07) }, - { AFMOVW, yfmvf, Px, 0xdf,(00),0xdf,(02) }, - { AFMOVWP, yfmvp, Px, 0xdf,(03) }, - { AFMOVX, yfmvx, Px, 0xdb,(05) }, - { AFMOVXP, yfmvp, Px, 0xdb,(07) }, - - { AFCOMB }, - { AFCOMBP }, - { AFCOMD, yfadd, Px, 0xdc,(02),0xd8,(02),0xdc,(02) }, /* botch */ - { AFCOMDP, yfadd, Px, 0xdc,(03),0xd8,(03),0xdc,(03) }, /* botch */ - { AFCOMDPP, ycompp, Px, 0xde,(03) }, - { AFCOMF, yfmvx, Px, 0xd8,(02) }, - { AFCOMFP, yfmvx, Px, 0xd8,(03) }, - { AFCOMI, yfmvx, Px, 0xdb,(06) }, - { AFCOMIP, yfmvx, Px, 0xdf,(06) }, - { AFCOML, yfmvx, Px, 0xda,(02) }, - { AFCOMLP, yfmvx, Px, 0xda,(03) }, - { AFCOMW, yfmvx, Px, 0xde,(02) }, - { AFCOMWP, yfmvx, Px, 0xde,(03) }, - - { AFUCOM, ycompp, Px, 0xdd,(04) }, - { AFUCOMI, ycompp, Px, 0xdb,(05) }, - { AFUCOMIP, ycompp, Px, 0xdf,(05) }, - { AFUCOMP, ycompp, Px, 0xdd,(05) }, - { AFUCOMPP, ycompp, Px, 0xda,(13) }, - - { AFADDDP, yfaddp, Px, 0xde,(00) }, - { AFADDW, yfmvx, Px, 0xde,(00) }, - { AFADDL, yfmvx, Px, 0xda,(00) }, - { AFADDF, yfmvx, Px, 0xd8,(00) }, - { AFADDD, yfadd, Px, 0xdc,(00),0xd8,(00),0xdc,(00) }, - - { AFMULDP, yfaddp, Px, 0xde,(01) }, - { AFMULW, yfmvx, Px, 0xde,(01) }, - { AFMULL, yfmvx, Px, 0xda,(01) }, - { AFMULF, yfmvx, Px, 0xd8,(01) }, - { AFMULD, yfadd, Px, 0xdc,(01),0xd8,(01),0xdc,(01) }, - - { AFSUBDP, yfaddp, Px, 0xde,(05) }, - { AFSUBW, yfmvx, Px, 0xde,(04) }, - { AFSUBL, yfmvx, Px, 0xda,(04) }, - { AFSUBF, yfmvx, Px, 0xd8,(04) }, - { AFSUBD, yfadd, Px, 0xdc,(04),0xd8,(04),0xdc,(05) }, - - { AFSUBRDP, yfaddp, Px, 0xde,(04) }, - { AFSUBRW, yfmvx, Px, 0xde,(05) }, - { AFSUBRL, yfmvx, Px, 0xda,(05) }, - { AFSUBRF, yfmvx, Px, 0xd8,(05) }, - { AFSUBRD, yfadd, Px, 0xdc,(05),0xd8,(05),0xdc,(04) }, - - { AFDIVDP, yfaddp, Px, 0xde,(07) }, - { AFDIVW, yfmvx, Px, 0xde,(06) }, - { AFDIVL, yfmvx, Px, 0xda,(06) }, - { AFDIVF, yfmvx, Px, 0xd8,(06) }, - { AFDIVD, yfadd, Px, 0xdc,(06),0xd8,(06),0xdc,(07) }, - - { AFDIVRDP, yfaddp, Px, 0xde,(06) }, - { AFDIVRW, yfmvx, Px, 0xde,(07) }, - { AFDIVRL, yfmvx, Px, 0xda,(07) }, - { AFDIVRF, yfmvx, Px, 0xd8,(07) }, - { AFDIVRD, yfadd, Px, 0xdc,(07),0xd8,(07),0xdc,(06) }, - - { AFXCHD, yfxch, Px, 0xd9,(01),0xd9,(01) }, - { AFFREE }, - { AFLDCW, ystcw, Px, 0xd9,(05),0xd9,(05) }, - { AFLDENV, ystcw, Px, 0xd9,(04),0xd9,(04) }, - { AFRSTOR, ysvrs, Px, 0xdd,(04),0xdd,(04) }, - { AFSAVE, ysvrs, Px, 0xdd,(06),0xdd,(06) }, - { AFSTCW, ystcw, Px, 0xd9,(07),0xd9,(07) }, - { AFSTENV, ystcw, Px, 0xd9,(06),0xd9,(06) }, - { AFSTSW, ystsw, Px, 0xdd,(07),0xdf,0xe0 }, - { AF2XM1, ynone, Px, 0xd9, 0xf0 }, - { AFABS, ynone, Px, 0xd9, 0xe1 }, - { AFCHS, ynone, Px, 0xd9, 0xe0 }, - { AFCLEX, ynone, Px, 0xdb, 0xe2 }, - { AFCOS, ynone, Px, 0xd9, 0xff }, - { AFDECSTP, ynone, Px, 0xd9, 0xf6 }, - { AFINCSTP, ynone, Px, 0xd9, 0xf7 }, - { AFINIT, ynone, Px, 0xdb, 0xe3 }, - { AFLD1, ynone, Px, 0xd9, 0xe8 }, - { AFLDL2E, ynone, Px, 0xd9, 0xea }, - { AFLDL2T, ynone, Px, 0xd9, 0xe9 }, - { AFLDLG2, ynone, Px, 0xd9, 0xec }, - { AFLDLN2, ynone, Px, 0xd9, 0xed }, - { AFLDPI, ynone, Px, 0xd9, 0xeb }, - { AFLDZ, ynone, Px, 0xd9, 0xee }, - { AFNOP, ynone, Px, 0xd9, 0xd0 }, - { AFPATAN, ynone, Px, 0xd9, 0xf3 }, - { AFPREM, ynone, Px, 0xd9, 0xf8 }, - { AFPREM1, ynone, Px, 0xd9, 0xf5 }, - { AFPTAN, ynone, Px, 0xd9, 0xf2 }, - { AFRNDINT, ynone, Px, 0xd9, 0xfc }, - { AFSCALE, ynone, Px, 0xd9, 0xfd }, - { AFSIN, ynone, Px, 0xd9, 0xfe }, - { AFSINCOS, ynone, Px, 0xd9, 0xfb }, - { AFSQRT, ynone, Px, 0xd9, 0xfa }, - { AFTST, ynone, Px, 0xd9, 0xe4 }, - { AFXAM, ynone, Px, 0xd9, 0xe5 }, - { AFXTRACT, ynone, Px, 0xd9, 0xf4 }, - { AFYL2X, ynone, Px, 0xd9, 0xf1 }, - { AFYL2XP1, ynone, Px, 0xd9, 0xf9 }, - { AEND }, - { ADYNT_ }, - { AINIT_ }, - { ASIGNAME }, - { ACMPXCHGB, yrb_mb, Pm, 0xb0 }, - { ACMPXCHGL, yrl_ml, Pm, 0xb1 }, - { ACMPXCHGW, yrl_ml, Pm, 0xb1 }, - { ACMPXCHG8B, yscond, Pm, 0xc7,(01) }, - - { ACPUID, ynone, Pm, 0xa2 }, - { ARDTSC, ynone, Pm, 0x31 }, - - { AXADDB, yrb_mb, Pb, 0x0f,0xc0 }, - { AXADDL, yrl_ml, Pm, 0xc1 }, - { AXADDW, yrl_ml, Pe, 0x0f,0xc1 }, - - { ACMOVLCC, yml_rl, Pm, 0x43 }, - { ACMOVLCS, yml_rl, Pm, 0x42 }, - { ACMOVLEQ, yml_rl, Pm, 0x44 }, - { ACMOVLGE, yml_rl, Pm, 0x4d }, - { ACMOVLGT, yml_rl, Pm, 0x4f }, - { ACMOVLHI, yml_rl, Pm, 0x47 }, - { ACMOVLLE, yml_rl, Pm, 0x4e }, - { ACMOVLLS, yml_rl, Pm, 0x46 }, - { ACMOVLLT, yml_rl, Pm, 0x4c }, - { ACMOVLMI, yml_rl, Pm, 0x48 }, - { ACMOVLNE, yml_rl, Pm, 0x45 }, - { ACMOVLOC, yml_rl, Pm, 0x41 }, - { ACMOVLOS, yml_rl, Pm, 0x40 }, - { ACMOVLPC, yml_rl, Pm, 0x4b }, - { ACMOVLPL, yml_rl, Pm, 0x49 }, - { ACMOVLPS, yml_rl, Pm, 0x4a }, - { ACMOVWCC, yml_rl, Pq, 0x43 }, - { ACMOVWCS, yml_rl, Pq, 0x42 }, - { ACMOVWEQ, yml_rl, Pq, 0x44 }, - { ACMOVWGE, yml_rl, Pq, 0x4d }, - { ACMOVWGT, yml_rl, Pq, 0x4f }, - { ACMOVWHI, yml_rl, Pq, 0x47 }, - { ACMOVWLE, yml_rl, Pq, 0x4e }, - { ACMOVWLS, yml_rl, Pq, 0x46 }, - { ACMOVWLT, yml_rl, Pq, 0x4c }, - { ACMOVWMI, yml_rl, Pq, 0x48 }, - { ACMOVWNE, yml_rl, Pq, 0x45 }, - { ACMOVWOC, yml_rl, Pq, 0x41 }, - { ACMOVWOS, yml_rl, Pq, 0x40 }, - { ACMOVWPC, yml_rl, Pq, 0x4b }, - { ACMOVWPL, yml_rl, Pq, 0x49 }, - { ACMOVWPS, yml_rl, Pq, 0x4a }, - - { AFCMOVCC, yfcmv, Px, 0xdb,(00) }, - { AFCMOVCS, yfcmv, Px, 0xda,(00) }, - { AFCMOVEQ, yfcmv, Px, 0xda,(01) }, - { AFCMOVHI, yfcmv, Px, 0xdb,(02) }, - { AFCMOVLS, yfcmv, Px, 0xda,(02) }, - { AFCMOVNE, yfcmv, Px, 0xdb,(01) }, - { AFCMOVNU, yfcmv, Px, 0xdb,(03) }, - { AFCMOVUN, yfcmv, Px, 0xda,(03) }, - - { ALFENCE, ynone, Pm, 0xae,0xe8 }, - { AMFENCE, ynone, Pm, 0xae,0xf0 }, - { ASFENCE, ynone, Pm, 0xae,0xf8 }, - - { AEMMS, ynone, Pm, 0x77 }, - - { APREFETCHT0, yprefetch, Pm, 0x18,(01) }, - { APREFETCHT1, yprefetch, Pm, 0x18,(02) }, - { APREFETCHT2, yprefetch, Pm, 0x18,(03) }, - { APREFETCHNTA, yprefetch, Pm, 0x18,(00) }, - - { ABSWAPL, ybswap, Pm, 0xc8 }, - - { AUNDEF, ynone, Px, 0x0f, 0x0b }, - - { AADDPD, yxm, Pq, 0x58 }, - { AADDPS, yxm, Pm, 0x58 }, - { AADDSD, yxm, Pf2, 0x58 }, - { AADDSS, yxm, Pf3, 0x58 }, - { AANDNPD, yxm, Pq, 0x55 }, - { AANDNPS, yxm, Pm, 0x55 }, - { AANDPD, yxm, Pq, 0x54 }, - { AANDPS, yxm, Pq, 0x54 }, - { ACMPPD, yxcmpi, Px, Pe,0xc2 }, - { ACMPPS, yxcmpi, Pm, 0xc2,0 }, - { ACMPSD, yxcmpi, Px, Pf2,0xc2 }, - { ACMPSS, yxcmpi, Px, Pf3,0xc2 }, - { ACOMISD, yxcmp, Pe, 0x2f }, - { ACOMISS, yxcmp, Pm, 0x2f }, - { ACVTPL2PD, yxcvm2, Px, Pf3,0xe6,Pe,0x2a }, - { ACVTPL2PS, yxcvm2, Pm, 0x5b,0,0x2a,0, }, - { ACVTPD2PL, yxcvm1, Px, Pf2,0xe6,Pe,0x2d }, - { ACVTPD2PS, yxm, Pe, 0x5a }, - { ACVTPS2PL, yxcvm1, Px, Pe,0x5b,Pm,0x2d }, - { ACVTPS2PD, yxm, Pm, 0x5a }, - { ACVTSD2SL, yxcvfl, Pf2, 0x2d }, - { ACVTSD2SS, yxm, Pf2, 0x5a }, - { ACVTSL2SD, yxcvlf, Pf2, 0x2a }, - { ACVTSL2SS, yxcvlf, Pf3, 0x2a }, - { ACVTSS2SD, yxm, Pf3, 0x5a }, - { ACVTSS2SL, yxcvfl, Pf3, 0x2d }, - { ACVTTPD2PL, yxcvm1, Px, Pe,0xe6,Pe,0x2c }, - { ACVTTPS2PL, yxcvm1, Px, Pf3,0x5b,Pm,0x2c }, - { ACVTTSD2SL, yxcvfl, Pf2, 0x2c }, - { ACVTTSS2SL, yxcvfl, Pf3, 0x2c }, - { ADIVPD, yxm, Pe, 0x5e }, - { ADIVPS, yxm, Pm, 0x5e }, - { ADIVSD, yxm, Pf2, 0x5e }, - { ADIVSS, yxm, Pf3, 0x5e }, - { AMASKMOVOU, yxr, Pe, 0xf7 }, - { AMAXPD, yxm, Pe, 0x5f }, - { AMAXPS, yxm, Pm, 0x5f }, - { AMAXSD, yxm, Pf2, 0x5f }, - { AMAXSS, yxm, Pf3, 0x5f }, - { AMINPD, yxm, Pe, 0x5d }, - { AMINPS, yxm, Pm, 0x5d }, - { AMINSD, yxm, Pf2, 0x5d }, - { AMINSS, yxm, Pf3, 0x5d }, - { AMOVAPD, yxmov, Pe, 0x28,0x29 }, - { AMOVAPS, yxmov, Pm, 0x28,0x29 }, - { AMOVO, yxmov, Pe, 0x6f,0x7f }, - { AMOVOU, yxmov, Pf3, 0x6f,0x7f }, - { AMOVHLPS, yxr, Pm, 0x12 }, - { AMOVHPD, yxmov, Pe, 0x16,0x17 }, - { AMOVHPS, yxmov, Pm, 0x16,0x17 }, - { AMOVLHPS, yxr, Pm, 0x16 }, - { AMOVLPD, yxmov, Pe, 0x12,0x13 }, - { AMOVLPS, yxmov, Pm, 0x12,0x13 }, - { AMOVMSKPD, yxrrl, Pq, 0x50 }, - { AMOVMSKPS, yxrrl, Pm, 0x50 }, - { AMOVNTO, yxr_ml, Pe, 0xe7 }, - { AMOVNTPD, yxr_ml, Pe, 0x2b }, - { AMOVNTPS, yxr_ml, Pm, 0x2b }, - { AMOVSD, yxmov, Pf2, 0x10,0x11 }, - { AMOVSS, yxmov, Pf3, 0x10,0x11 }, - { AMOVUPD, yxmov, Pe, 0x10,0x11 }, - { AMOVUPS, yxmov, Pm, 0x10,0x11 }, - { AMULPD, yxm, Pe, 0x59 }, - { AMULPS, yxm, Ym, 0x59 }, - { AMULSD, yxm, Pf2, 0x59 }, - { AMULSS, yxm, Pf3, 0x59 }, - { AORPD, yxm, Pq, 0x56 }, - { AORPS, yxm, Pm, 0x56 }, - { APADDQ, yxm, Pe, 0xd4 }, - { APAND, yxm, Pe, 0xdb }, - { APCMPEQB, yxmq, Pe ,0x74 }, - { APMAXSW, yxm, Pe, 0xee }, - { APMAXUB, yxm, Pe, 0xde }, - { APMINSW, yxm, Pe, 0xea }, - { APMINUB, yxm, Pe, 0xda }, - { APMOVMSKB, ymskb, Px, Pe,0xd7,0xd7 }, - { APSADBW, yxm, Pq, 0xf6 }, - { APSUBB, yxm, Pe, 0xf8 }, - { APSUBL, yxm, Pe, 0xfa }, - { APSUBQ, yxm, Pe, 0xfb }, - { APSUBSB, yxm, Pe, 0xe8 }, - { APSUBSW, yxm, Pe, 0xe9 }, - { APSUBUSB, yxm, Pe, 0xd8 }, - { APSUBUSW, yxm, Pe, 0xd9 }, - { APSUBW, yxm, Pe, 0xf9 }, - { APUNPCKHQDQ, yxm, Pe, 0x6d }, - { APUNPCKLQDQ, yxm, Pe, 0x6c }, - { ARCPPS, yxm, Pm, 0x53 }, - { ARCPSS, yxm, Pf3, 0x53 }, - { ARSQRTPS, yxm, Pm, 0x52 }, - { ARSQRTSS, yxm, Pf3, 0x52 }, - { ASQRTPD, yxm, Pe, 0x51 }, - { ASQRTPS, yxm, Pm, 0x51 }, - { ASQRTSD, yxm, Pf2, 0x51 }, - { ASQRTSS, yxm, Pf3, 0x51 }, - { ASUBPD, yxm, Pe, 0x5c }, - { ASUBPS, yxm, Pm, 0x5c }, - { ASUBSD, yxm, Pf2, 0x5c }, - { ASUBSS, yxm, Pf3, 0x5c }, - { AUCOMISD, yxcmp, Pe, 0x2e }, - { AUCOMISS, yxcmp, Pm, 0x2e }, - { AUNPCKHPD, yxm, Pe, 0x15 }, - { AUNPCKHPS, yxm, Pm, 0x15 }, - { AUNPCKLPD, yxm, Pe, 0x14 }, - { AUNPCKLPS, yxm, Pm, 0x14 }, - { AXORPD, yxm, Pe, 0x57 }, - { AXORPS, yxm, Pm, 0x57 }, - - { AAESENC, yaes, Pq, 0x38,0xdc,(0) }, - { APINSRD, yinsrd, Pq, 0x3a, 0x22, (00) }, - { APSHUFB, ymshufb,Pq, 0x38, 0x00 }, - - { AUSEFIELD, ynop, Px, 0,0 }, - { ATYPE }, - { AFUNCDATA, yfuncdata, Px, 0,0 }, - { APCDATA, ypcdata, Px, 0,0 }, - - 0 -}; diff --git a/src/cmd/8l/pass.c b/src/cmd/8l/pass.c deleted file mode 100644 index 1eaf78fe0..000000000 --- a/src/cmd/8l/pass.c +++ /dev/null @@ -1,858 +0,0 @@ -// Inferno utils/8l/pass.c -// http://code.google.com/p/inferno-os/source/browse/utils/8l/pass.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. - -// Code and data passes. - -#include "l.h" -#include "../ld/lib.h" -#include "../../pkg/runtime/stack.h" - -static void xfol(Prog*, Prog**); - -Prog* -brchain(Prog *p) -{ - int i; - - for(i=0; i<20; i++) { - if(p == P || p->as != AJMP) - return p; - p = p->pcond; - } - return P; -} - -void -follow(void) -{ - Prog *firstp, *lastp; - - if(debug['v']) - Bprint(&bso, "%5.2f follow\n", cputime()); - Bflush(&bso); - - for(cursym = textp; cursym != nil; cursym = cursym->next) { - firstp = prg(); - lastp = firstp; - xfol(cursym->text, &lastp); - lastp->link = nil; - cursym->text = firstp->link; - } -} - -static int -nofollow(int a) -{ - switch(a) { - case AJMP: - case ARET: - case AIRETL: - case AIRETW: - case AUNDEF: - 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; - enum as a; - -loop: - if(p == P) - return; - 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) { - /* - * 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 == *last) - break; - a = q->as; - if(a == ANOP) { - i--; - continue; - } - 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) - continue; - for(;;) { - if(p->as == ANOP) { - p = p->link; - continue; - } - q = copyp(p); - p = p->link; - q->mark = 1; - (*last)->link = q; - *last = q; - if(q->as != a || q->pcond == P || q->pcond->mark) - continue; - - q->as = relinv(q->as); - p = q->pcond; - q->pcond = q->link; - q->link = p; - xfol(q->link, last); - p = q->link; - if(p->mark) - return; - goto loop; - } - } /* */ - q = prg(); - q->as = AJMP; - q->line = p->line; - q->to.type = D_BRANCH; - q->to.offset = p->pc; - q->pcond = p; - p = q; - } - - /* emit p */ - p->mark = 1; - (*last)->link = p; - *last = p; - a = p->as; - - /* continue loop with what comes after p */ - if(nofollow(a)) - return; - if(p->pcond != P && a != ACALL) { - /* - * some kind of conditional branch. - * recurse to follow one path. - * continue loop on the other. - */ - if((q = brchain(p->pcond)) != P) - p->pcond = q; - if((q = brchain(p->link)) != P) - p->link = q; - if(p->from.type == D_CONST) { - if(p->from.offset == 1) { - /* - * expect conditional jump to be taken. - * rewrite so that's the fall-through case. - */ - p->as = relinv(a); - q = p->link; - p->link = p->pcond; - p->pcond = q; - } - } else { - q = p->link; - if(q->mark) - if(a != ALOOP) { - p->as = relinv(a); - p->link = p->pcond; - p->pcond = q; - } - } - xfol(p->link, last); - if(p->pcond->mark) - return; - p = p->pcond; - goto loop; - } - p = p->link; - goto loop; -} - -int -relinv(int a) -{ - - switch(a) { - case AJEQ: return AJNE; - case AJNE: return AJEQ; - case AJLE: return AJGT; - case AJLS: return AJHI; - case AJLT: return AJGE; - case AJMI: return AJPL; - case AJGE: return AJLT; - case AJPL: return AJMI; - case AJGT: return AJLE; - case AJHI: return AJLS; - case AJCS: return AJCC; - case AJCC: return AJCS; - case AJPS: return AJPC; - case AJPC: return AJPS; - case AJOS: return AJOC; - case AJOC: return AJOS; - } - diag("unknown relation: %s in %s", anames[a], TNAME); - return a; -} - -void -patch(void) -{ - int32 c; - Prog *p, *q; - Sym *s; - int32 vexit; - Sym *plan9_tos; - - if(debug['v']) - Bprint(&bso, "%5.2f mkfwd\n", cputime()); - Bflush(&bso); - mkfwd(); - if(debug['v']) - Bprint(&bso, "%5.2f patch\n", cputime()); - Bflush(&bso); - s = lookup("exit", 0); - vexit = s->value; - - plan9_tos = S; - if(HEADTYPE == Hplan9x32) - plan9_tos = lookup("_tos", 0); - - for(cursym = textp; cursym != nil; cursym = cursym->next) { - for(p = cursym->text; p != P; p = p->link) { - if(HEADTYPE == Hwindows) { - // Convert - // op n(GS), reg - // to - // MOVL 0x14(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 = 0x14; - } - } - if(HEADTYPE == Hlinux) { - // 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. - // In external mode we just produce a reloc. - if(p->from.type == D_INDIR+D_GS && p->from.offset < 0 - && p->to.type >= D_AX && p->to.type <= D_DI) { - if(linkmode != LinkExternal) { - 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; - } else { - // Add signals to relocate. - p->from.index = D_GS; - p->from.scale = 1; - } - } - } - if(HEADTYPE == Hplan9x32) { - 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_EXTERN; - p->from.sym = plan9_tos; - p->from.offset = 0; - } - } - if((p->as == ACALL && p->to.type != D_BRANCH) || (p->as == AJMP && p->to.type != D_BRANCH) || (p->as == ARET && p->to.sym != nil)) { - s = p->to.sym; - if(p->to.type == D_INDIR+D_ADDR) { - /* skip check if this is an indirect call (CALL *symbol(SB)) */ - continue; - } else if(s) { - if(debug['c']) - Bprint(&bso, "%s calls %s\n", TNAME, s->name); - if((s->type&SMASK) != 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(q == P) { - diag("branch out of range in %s (%#ux)\n%P [%s]", - TNAME, c, p, p->to.sym ? p->to.sym->name : ""); - p->to.type = D_NONE; - } - p->pcond = q; - } - } - - for(cursym = textp; cursym != nil; cursym = cursym->next) { - if(cursym->text == nil || cursym->p != nil) - continue; - - 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; - } - } - } -} - -Prog* -brloop(Prog *p) -{ - int c; - Prog *q; - - c = 0; - for(q = p; q != P; q = q->pcond) { - if(q->as != AJMP) - break; - c++; - if(c >= 5000) - return P; - } - return q; -} - -static Prog* load_g_cx(Prog*); -static Prog* stacksplit(Prog*, int32, Prog**); - -static Sym *plan9_tos; -static Prog *pmorestack; -static Sym *symmorestack; - -void -dostkoff(void) -{ - Prog *p, *q; - int32 autoffset, deltasp; - int a; - - pmorestack = P; - symmorestack = lookup("runtime.morestack", 0); - - if(symmorestack->type != STEXT) - diag("runtime.morestack not defined"); - else { - pmorestack = symmorestack->text; - symmorestack->text->from.scale |= NOSPLIT; - } - - plan9_tos = S; - if(HEADTYPE == Hplan9x32) - plan9_tos = lookup("_tos", 0); - - for(cursym = textp; cursym != nil; cursym = cursym->next) { - if(cursym->text == nil || cursym->text->link == nil) - continue; - - p = cursym->text; - autoffset = p->to.offset; - if(autoffset < 0) - autoffset = 0; - - q = P; - - if(!(p->from.scale & NOSPLIT) || (p->from.scale & WRAPPER)) { - p = appendp(p); - p = load_g_cx(p); // load g into CX - } - if(!(cursym->text->from.scale & NOSPLIT)) - p = stacksplit(p, autoffset, &q); // emit split check - - if(autoffset) { - p = appendp(p); - p->as = AADJSP; - p->from.type = D_CONST; - p->from.offset = autoffset; - p->spadj = autoffset; - } else { - // zero-byte stack adjustment. - // Insert a fake non-zero adjustment so that stkcheck can - // recognize the end of the stack-splitting prolog. - p = appendp(p); - p->as = ANOP; - p->spadj = -PtrSize; - p = appendp(p); - p->as = ANOP; - p->spadj = PtrSize; - } - if(q != P) - q->pcond = p; - deltasp = autoffset; - - if(cursym->text->from.scale & WRAPPER) { - // g->panicwrap += autoffset + PtrSize; - p = appendp(p); - p->as = AADDL; - p->from.type = D_CONST; - p->from.offset = autoffset + PtrSize; - p->to.type = D_INDIR+D_CX; - p->to.offset = 2*PtrSize; - } - - if(debug['Z'] && autoffset && !(cursym->text->from.scale&NOSPLIT)) { - // 8l -Z means zero the stack frame on entry. - // This slows down function calls but can help avoid - // false positives in garbage collection. - p = appendp(p); - p->as = AMOVL; - p->from.type = D_SP; - p->to.type = D_DI; - - p = appendp(p); - p->as = AMOVL; - p->from.type = D_CONST; - p->from.offset = autoffset/4; - p->to.type = D_CX; - - p = appendp(p); - p->as = AMOVL; - p->from.type = D_CONST; - p->from.offset = 0; - p->to.type = D_AX; - - p = appendp(p); - p->as = AREP; - - p = appendp(p); - p->as = ASTOSL; - } - - 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(cursym->text->from.scale & WRAPPER) { - p = load_g_cx(p); - p = appendp(p); - // g->panicwrap -= autoffset + PtrSize; - p->as = ASUBL; - p->from.type = D_CONST; - p->from.offset = autoffset + PtrSize; - p->to.type = D_INDIR+D_CX; - p->to.offset = 2*PtrSize; - p = appendp(p); - p->as = ARET; - } - - if(autoffset) { - p->as = AADJSP; - p->from.type = D_CONST; - p->from.offset = -autoffset; - p->spadj = -autoffset; - p = appendp(p); - p->as = ARET; - // If there are instructions following - // this ARET, they come from a branch - // with the same stackframe, so undo - // the cleanup. - p->spadj = +autoffset; - } - if(p->to.sym) // retjmp - p->as = AJMP; - } - } -} - -// Append code to p to load g into cx. -// Overwrites p with the first instruction (no first appendp). -// Overwriting p is unusual but it lets use this in both the -// prologue (caller must call appendp first) and in the epilogue. -// Returns last new instruction. -static Prog* -load_g_cx(Prog *p) -{ - switch(HEADTYPE) { - case Hwindows: - p->as = AMOVL; - p->from.type = D_INDIR+D_FS; - p->from.offset = 0x14; - p->to.type = D_CX; - - p = appendp(p); - p->as = AMOVL; - p->from.type = D_INDIR+D_CX; - p->from.offset = 0; - p->to.type = D_CX; - break; - - case Hlinux: - if(linkmode != LinkExternal) { - p->as = AMOVL; - p->from.type = D_INDIR+D_GS; - p->from.offset = 0; - p->to.type = D_CX; - - p = appendp(p); - p->as = AMOVL; - p->from.type = D_INDIR+D_CX; - p->from.offset = tlsoffset + 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->from.index = D_GS; - p->from.scale = 1; - } - break; - - case Hplan9x32: - p->as = AMOVL; - p->from.type = D_EXTERN; - p->from.sym = plan9_tos; - p->to.type = D_CX; - - p = appendp(p); - p->as = AMOVL; - p->from.type = D_INDIR+D_CX; - p->from.offset = tlsoffset + 0; - 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; - } - return p; -} - -// Append code to p to check for stack split. -// Appends to (does not overwrite) p. -// Assumes g is in CX. -// Returns last new instruction. -// On return, *jmpok is the instruction that should jump -// to the stack frame allocation if no split is needed. -static Prog* -stacksplit(Prog *p, int32 framesize, Prog **jmpok) -{ - Prog *q, *q1; - int arg; - - 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 = AJCC; - 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; - - p = appendp(p); - p->as = ANOP; - q1->pcond = p; - } - q1 = P; - - if(framesize <= StackSmall) { - // small stack: SP <= stackguard - // CMPL SP, stackguard - p = appendp(p); - p->as = ACMPL; - p->from.type = D_SP; - p->to.type = D_INDIR+D_CX; - } else if(framesize <= StackBig) { - // large stack: SP-framesize <= stackguard-StackSmall - // LEAL -(framesize-StackSmall)(SP), AX - // CMPL AX, stackguard - p = appendp(p); - p->as = ALEAL; - p->from.type = D_INDIR+D_SP; - p->from.offset = -(framesize-StackSmall); - p->to.type = D_AX; - - p = appendp(p); - p->as = ACMPL; - p->from.type = D_AX; - p->to.type = D_INDIR+D_CX; - } else { - // Such a large stack we need to protect against wraparound - // if SP is close to zero. - // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall) - // The +StackGuard on both sides is required to keep the left side positive: - // SP is allowed to be slightly below stackguard. See stack.h. - // - // Preemption sets stackguard to StackPreempt, a very large value. - // That breaks the math above, so we have to check for that explicitly. - // MOVL stackguard, CX - // CMPL CX, $StackPreempt - // JEQ label-of-call-to-morestack - // LEAL StackGuard(SP), AX - // SUBL stackguard, AX - // CMPL AX, $(framesize+(StackGuard-StackSmall)) - p = appendp(p); - p->as = AMOVL; - p->from.type = D_INDIR+D_CX; - p->from.offset = 0; - p->to.type = D_SI; - - p = appendp(p); - p->as = ACMPL; - p->from.type = D_SI; - p->to.type = D_CONST; - p->to.offset = (uint32)StackPreempt; - - p = appendp(p); - p->as = AJEQ; - p->to.type = D_BRANCH; - q1 = p; - - p = appendp(p); - p->as = ALEAL; - p->from.type = D_INDIR+D_SP; - p->from.offset = StackGuard; - p->to.type = D_AX; - - p = appendp(p); - p->as = ASUBL; - p->from.type = D_SI; - p->from.offset = 0; - p->to.type = D_AX; - - p = appendp(p); - p->as = ACMPL; - p->from.type = D_AX; - p->to.type = D_CONST; - p->to.offset = framesize+(StackGuard-StackSmall); - } - - // common - p = appendp(p); - p->as = AJHI; - p->to.type = D_BRANCH; - p->to.offset = 4; - q = p; - - p = appendp(p); // save frame size in DI - p->as = AMOVL; - p->to.type = D_DI; - p->from.type = D_CONST; - - // If we ask for more stack, we'll get a minimum of StackMin bytes. - // We need a stack frame large enough to hold the top-of-stack data, - // the function arguments+results, our caller's PC, our frame, - // a word for the return PC of the next call, and then the StackLimit bytes - // that must be available on entry to any function called from a function - // that did a stack check. If StackMin is enough, don't ask for a specific - // amount: then we can use the custom functions and save a few - // instructions. - if(StackTop + cursym->text->to.offset2 + PtrSize + framesize + PtrSize + StackLimit >= StackMin) - p->from.offset = (framesize+7) & ~7LL; - - arg = cursym->text->to.offset2; - if(arg == 1) // special marker for known 0 - arg = 0; - if(arg&3) - diag("misaligned argument size in stack split"); - p = appendp(p); // save arg size in AX - p->as = AMOVL; - p->to.type = D_AX; - p->from.type = D_CONST; - p->from.offset = arg; - - p = appendp(p); - p->as = ACALL; - p->to.type = D_BRANCH; - p->pcond = pmorestack; - p->to.sym = symmorestack; - - p = appendp(p); - p->as = AJMP; - p->to.type = D_BRANCH; - p->pcond = cursym->text->link; - - if(q != P) - q->pcond = p->link; - if(q1 != P) - q1->pcond = q->link; - - *jmpok = q; - return p; -} - -int32 -atolwhex(char *s) -{ - int32 n; - int f; - - n = 0; - f = 0; - while(*s == ' ' || *s == '\t') - s++; - if(*s == '-' || *s == '+') { - if(*s++ == '-') - f = 1; - while(*s == ' ' || *s == '\t') - s++; - } - if(s[0]=='0' && s[1]){ - if(s[1]=='x' || s[1]=='X'){ - s += 2; - for(;;){ - if(*s >= '0' && *s <= '9') - n = n*16 + *s++ - '0'; - else if(*s >= 'a' && *s <= 'f') - n = n*16 + *s++ - 'a' + 10; - else if(*s >= 'A' && *s <= 'F') - n = n*16 + *s++ - 'A' + 10; - else - break; - } - } else - while(*s >= '0' && *s <= '7') - n = n*8 + *s++ - '0'; - } else - while(*s >= '0' && *s <= '9') - n = n*10 + *s++ - '0'; - if(f) - n = -n; - return n; -} diff --git a/src/cmd/8l/prof.c b/src/cmd/8l/prof.c deleted file mode 100644 index d99c5e408..000000000 --- a/src/cmd/8l/prof.c +++ /dev/null @@ -1,173 +0,0 @@ -// 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) -{ -#ifdef NOTDEF // 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 deleted file mode 100644 index acf973cab..000000000 --- a/src/cmd/8l/span.c +++ /dev/null @@ -1,1507 +0,0 @@ -// Inferno utils/8l/span.c -// http://code.google.com/p/inferno-os/source/browse/utils/8l/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. - -// Instruction layout. - -#include "l.h" -#include "../ld/lib.h" -#include "../ld/elf.h" - -static int32 vaddr(Adr*, Reloc*); - -void -span1(Sym *s) -{ - Prog *p, *q; - 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; - 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; - } - } - - 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; - } - if(q->as == AJCXZW) - s->p[q->pc+2] = v; - else - 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(); - } - } 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; inp; i++) { - print(" %.2ux", s->p[i]); - if(i%16 == 15) - print("\n %.6ux", i+1); - } - if(i%16) - print("\n"); - - for(i=0; inr; i++) { - Reloc *r; - - r = &s->r[i]; - print(" rel %#.4ux/%d %s%+d\n", r->off, r->siz, r->sym->name, r->add); - } - } -} - -void -span(void) -{ - Prog *p, *q; - int32 v; - int n; - - if(debug['v']) - Bprint(&bso, "%5.2f span\n", cputime()); - - // 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; - - // 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; - } - } - span1(cursym); - } -} - -void -xdefine(char *p, int t, int32 v) -{ - Sym *s; - - s = lookup(p, 0); - s->type = t; - s->value = v; - s->reachable = 1; - s->special = 1; -} - -void -instinit(void) -{ - int i; - - for(i=1; optab[i].as; i++) - if(i != optab[i].as) { - diag("phase error in optab: at %A found %A", i, optab[i].as); - errorexit(); - } - maxop = i; - - for(i=0; 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(i >= D_X0 && i <= D_X0+7) - reg[i] = (i-D_X0) & 7; - } -} - -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; - } - return 0; -} - -int -oclass(Adr *a) -{ - int32 v; - - if((a->type >= D_INDIR && a->type < 2*D_INDIR) || a->index != D_NONE) { - if(a->index != D_NONE && a->scale == 0) { - if(a->type == D_ADDR) { - switch(a->index) { - case D_EXTERN: - case D_STATIC: - return Yi32; - case D_AUTO: - case D_PARAM: - return Yiauto; - } - return Yxxx; - } - //if(a->type == D_INDIR+D_ADDR) - // print("*Ycol\n"); - return Ycol; - } - return Ym; - } - switch(a->type) - { - case D_AL: - return Yal; - - case D_AX: - return Yax; - - case D_CL: - case D_DL: - case D_BL: - case D_AH: - case D_CH: - case D_DH: - case D_BH: - return Yrb; - - case D_CX: - return Ycx; - - case D_DX: - case D_BX: - return Yrx; - - case D_SP: - case D_BP: - case D_SI: - case D_DI: - return Yrl; - - case D_F0+0: - return Yf0; - - case D_F0+1: - case D_F0+2: - case D_F0+3: - case D_F0+4: - case D_F0+5: - case D_F0+6: - case D_F0+7: - return Yrf; - - case D_X0+0: - case D_X0+1: - case D_X0+2: - case D_X0+3: - case D_X0+4: - case D_X0+5: - case D_X0+6: - case D_X0+7: - return Yxr; - - case D_NONE: - return Ynone; - - case D_CS: return Ycs; - case D_SS: return Yss; - case D_DS: return Yds; - case D_ES: return Yes; - case D_FS: return Yfs; - case D_GS: return Ygs; - - case D_GDTR: return Ygdtr; - case D_IDTR: return Yidtr; - case D_LDTR: return Yldtr; - case D_MSW: return Ymsw; - case D_TASK: return Ytask; - - case D_CR+0: return Ycr0; - case D_CR+1: return Ycr1; - case D_CR+2: return Ycr2; - case D_CR+3: return Ycr3; - case D_CR+4: return Ycr4; - case D_CR+5: return Ycr5; - case D_CR+6: return Ycr6; - case D_CR+7: return Ycr7; - - case D_DR+0: return Ydr0; - case D_DR+1: return Ydr1; - case D_DR+2: return Ydr2; - case D_DR+3: return Ydr3; - case D_DR+4: return Ydr4; - case D_DR+5: return Ydr5; - case D_DR+6: return Ydr6; - case D_DR+7: return Ydr7; - - case D_TR+0: return Ytr0; - case D_TR+1: return Ytr1; - case D_TR+2: return Ytr2; - case D_TR+3: return Ytr3; - case D_TR+4: return Ytr4; - case D_TR+5: return Ytr5; - case D_TR+6: return Ytr6; - case D_TR+7: return Ytr7; - - case D_EXTERN: - case D_STATIC: - case D_AUTO: - case D_PARAM: - return Ym; - - case D_CONST: - case D_CONST2: - case D_ADDR: - if(a->sym == S) { - v = a->offset; - if(v == 0) - return Yi0; - if(v == 1) - return Yi1; - if(v >= -128 && v <= 127) - return Yi8; - } - return Yi32; - - case D_BRANCH: - return Ybr; - } - return Yxxx; -} - -void -asmidx(int scale, int index, int base) -{ - int i; - - switch(index) { - default: - goto bad; - - case D_NONE: - i = 4 << 3; - goto bas; - - case D_AX: - case D_CX: - case D_DX: - case D_BX: - case D_BP: - case D_SI: - case D_DI: - i = reg[index] << 3; - break; - } - switch(scale) { - default: - goto bad; - case 1: - break; - case 2: - i |= (1<<6); - break; - case 4: - i |= (2<<6); - break; - case 8: - i |= (3<<6); - break; - } -bas: - switch(base) { - default: - goto bad; - case D_NONE: /* must be mod=00 */ - i |= 5; - break; - case D_AX: - case D_CX: - case D_DX: - case D_BX: - case D_SP: - case D_BP: - case D_SI: - case D_DI: - i |= reg[base]; - break; - } - *andptr++ = i; - return; -bad: - diag("asmidx: bad address %d,%d,%d", scale, index, base); - *andptr++ = 0; - return; -} - -static void -put4(int32 v) -{ - andptr[0] = v; - andptr[1] = v>>8; - andptr[2] = v>>16; - andptr[3] = v>>24; - 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) -{ - if(!s->reachable) - diag("unreachable symbol in symaddr - %s", s->name); - return s->value; -} - -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; - if(t == D_ADDR) - t = a->index; - switch(t) { - case D_STATIC: - case D_EXTERN: - s = a->sym; - if(s != nil) { - 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; -} - -static int -istls(Adr *a) -{ - if(HEADTYPE == Hlinux) - return a->index == D_GS; - return a->type == D_INDIR+D_GS; -} - -void -asmand(Adr *a, int r) -{ - int32 v; - int t, scale; - Reloc rel; - - v = a->offset; - t = a->type; - rel.siz = 0; - if(a->index != D_NONE && a->index != D_FS && a->index != D_GS) { - 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; - } - } 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; - } - *andptr++ = (2 << 6) | (4 << 0) | (r << 3); - asmidx(a->scale, a->index, t); - goto putrelv; - } - if(t >= D_AL && t <= D_F7 || t >= D_X0 && t <= D_X7) { - 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: - t = D_NONE; - v = vaddr(a, &rel); - break; - case D_AUTO: - case D_PARAM: - t = D_SP; - break; - } - scale = 1; - } else - t -= D_INDIR; - - 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(v >= -128 && v < 128 && rel.siz == 0) { - *andptr++ = (1 << 6) | (4 << 0) | (r << 3); - asmidx(scale, D_NONE, t); - *andptr++ = v; - return; - } - *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; - } - if(v >= -128 && v < 128 && rel.siz == 0 && a->index != D_FS && a->index != D_GS) { - 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; - } - 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; - } else if(iself && linkmode == LinkExternal && istls(a) && HEADTYPE != Hopenbsd) { - Reloc *r; - Sym *s; - - r = addrel(cursym); - r->off = curp->pc + andptr - and; - r->add = a->offset-tlsoffset; - r->xadd = r->add; - r->siz = 4; - r->type = D_TLS; - s = lookup("runtime.tlsgm", 0); - r->sym = s; - r->xsym = s; - v = 0; - } - - put4(v); - return; - -bad: - diag("asmand: bad address %D", a); - return; -} - -#define E 0xff -uchar ymovtab[] = -{ -/* push */ - APUSHL, Ycs, Ynone, 0, 0x0e,E,0,0, - APUSHL, Yss, Ynone, 0, 0x16,E,0,0, - APUSHL, Yds, Ynone, 0, 0x1e,E,0,0, - APUSHL, Yes, Ynone, 0, 0x06,E,0,0, - APUSHL, Yfs, Ynone, 0, 0x0f,0xa0,E,0, - APUSHL, Ygs, Ynone, 0, 0x0f,0xa8,E,0, - - APUSHW, Ycs, Ynone, 0, Pe,0x0e,E,0, - APUSHW, Yss, Ynone, 0, Pe,0x16,E,0, - APUSHW, Yds, Ynone, 0, Pe,0x1e,E,0, - APUSHW, Yes, Ynone, 0, Pe,0x06,E,0, - APUSHW, Yfs, Ynone, 0, Pe,0x0f,0xa0,E, - APUSHW, Ygs, Ynone, 0, Pe,0x0f,0xa8,E, - -/* pop */ - APOPL, Ynone, Yds, 0, 0x1f,E,0,0, - APOPL, Ynone, Yes, 0, 0x07,E,0,0, - APOPL, Ynone, Yss, 0, 0x17,E,0,0, - APOPL, Ynone, Yfs, 0, 0x0f,0xa1,E,0, - APOPL, Ynone, Ygs, 0, 0x0f,0xa9,E,0, - - APOPW, Ynone, Yds, 0, Pe,0x1f,E,0, - APOPW, Ynone, Yes, 0, Pe,0x07,E,0, - APOPW, Ynone, Yss, 0, Pe,0x17,E,0, - APOPW, Ynone, Yfs, 0, Pe,0x0f,0xa1,E, - APOPW, Ynone, Ygs, 0, Pe,0x0f,0xa9,E, - -/* mov seg */ - AMOVW, Yes, Yml, 1, 0x8c,0,0,0, - AMOVW, Ycs, Yml, 1, 0x8c,1,0,0, - AMOVW, Yss, Yml, 1, 0x8c,2,0,0, - AMOVW, Yds, Yml, 1, 0x8c,3,0,0, - AMOVW, Yfs, Yml, 1, 0x8c,4,0,0, - AMOVW, Ygs, Yml, 1, 0x8c,5,0,0, - - AMOVW, Yml, Yes, 2, 0x8e,0,0,0, - AMOVW, Yml, Ycs, 2, 0x8e,1,0,0, - AMOVW, Yml, Yss, 2, 0x8e,2,0,0, - AMOVW, Yml, Yds, 2, 0x8e,3,0,0, - AMOVW, Yml, Yfs, 2, 0x8e,4,0,0, - AMOVW, Yml, Ygs, 2, 0x8e,5,0,0, - -/* mov cr */ - AMOVL, Ycr0, Yml, 3, 0x0f,0x20,0,0, - AMOVL, Ycr2, Yml, 3, 0x0f,0x20,2,0, - AMOVL, Ycr3, Yml, 3, 0x0f,0x20,3,0, - AMOVL, Ycr4, Yml, 3, 0x0f,0x20,4,0, - - AMOVL, Yml, Ycr0, 4, 0x0f,0x22,0,0, - AMOVL, Yml, Ycr2, 4, 0x0f,0x22,2,0, - AMOVL, Yml, Ycr3, 4, 0x0f,0x22,3,0, - AMOVL, Yml, Ycr4, 4, 0x0f,0x22,4,0, - -/* mov dr */ - AMOVL, Ydr0, Yml, 3, 0x0f,0x21,0,0, - AMOVL, Ydr6, Yml, 3, 0x0f,0x21,6,0, - AMOVL, Ydr7, Yml, 3, 0x0f,0x21,7,0, - - AMOVL, Yml, Ydr0, 4, 0x0f,0x23,0,0, - AMOVL, Yml, Ydr6, 4, 0x0f,0x23,6,0, - AMOVL, Yml, Ydr7, 4, 0x0f,0x23,7,0, - -/* mov tr */ - AMOVL, Ytr6, Yml, 3, 0x0f,0x24,6,0, - AMOVL, Ytr7, Yml, 3, 0x0f,0x24,7,0, - - AMOVL, Yml, Ytr6, 4, 0x0f,0x26,6,E, - AMOVL, Yml, Ytr7, 4, 0x0f,0x26,7,E, - -/* lgdt, sgdt, lidt, sidt */ - AMOVL, Ym, Ygdtr, 4, 0x0f,0x01,2,0, - AMOVL, Ygdtr, Ym, 3, 0x0f,0x01,0,0, - AMOVL, Ym, Yidtr, 4, 0x0f,0x01,3,0, - AMOVL, Yidtr, Ym, 3, 0x0f,0x01,1,0, - -/* lldt, sldt */ - AMOVW, Yml, Yldtr, 4, 0x0f,0x00,2,0, - AMOVW, Yldtr, Yml, 3, 0x0f,0x00,0,0, - -/* lmsw, smsw */ - AMOVW, Yml, Ymsw, 4, 0x0f,0x01,6,0, - AMOVW, Ymsw, Yml, 3, 0x0f,0x01,4,0, - -/* ltr, str */ - AMOVW, Yml, Ytask, 4, 0x0f,0x00,3,0, - AMOVW, Ytask, Yml, 3, 0x0f,0x00,1,0, - -/* load full pointer */ - AMOVL, Yml, Ycol, 5, 0,0,0,0, - AMOVW, Yml, Ycol, 5, Pe,0,0,0, - -/* double shift */ - ASHLL, Ycol, Yml, 6, 0xa4,0xa5,0,0, - ASHRL, Ycol, Yml, 6, 0xac,0xad,0,0, - -/* extra imul */ - AIMULW, Yml, Yrl, 7, Pq,0xaf,0,0, - AIMULL, Yml, Yrl, 7, Pm,0xaf,0,0, - 0 -}; - -// byteswapreg returns a byte-addressable register (AX, BX, CX, DX) -// which is not referenced in a->type. -// If a is empty, it returns BX to account for MULB-like instructions -// that might use DX and AX. -int -byteswapreg(Adr *a) -{ - int cana, canb, canc, cand; - - cana = canb = canc = cand = 1; - - switch(a->type) { - case D_NONE: - cana = cand = 0; - break; - case D_AX: - case D_AL: - case D_AH: - case D_INDIR+D_AX: - cana = 0; - break; - case D_BX: - case D_BL: - case D_BH: - case D_INDIR+D_BX: - canb = 0; - break; - case D_CX: - case D_CL: - case D_CH: - case D_INDIR+D_CX: - canc = 0; - break; - case D_DX: - case D_DL: - case D_DH: - case D_INDIR+D_DX: - cand = 0; - break; - } - switch(a->index) { - case D_AX: - cana = 0; - break; - case D_BX: - canb = 0; - break; - case D_CX: - canc = 0; - break; - case D_DX: - cand = 0; - break; - } - if(cana) - return D_AX; - if(canb) - return D_BX; - if(canc) - return D_CX; - if(cand) - return D_DX; - - diag("impossible byte register"); - errorexit(); - return 0; -} - -void -subreg(Prog *p, int from, int to) -{ - - if(debug['Q']) - print("\n%P s/%R/%R/\n", p, from, to); - - if(p->from.type == from) { - p->from.type = to; - p->ft = 0; - } - if(p->to.type == from) { - p->to.type = to; - p->tt = 0; - } - - if(p->from.index == from) { - p->from.index = to; - p->ft = 0; - } - if(p->to.index == from) { - p->to.index = to; - p->tt = 0; - } - - from += D_INDIR; - if(p->from.type == from) { - p->from.type = to+D_INDIR; - p->ft = 0; - } - if(p->to.type == from) { - p->to.type = to+D_INDIR; - p->tt = 0; - } - - if(debug['Q']) - print("%P\n", p); -} - -static int -mediaop(Optab *o, int op, int osize, int z) -{ - switch(op){ - case Pm: - case Pe: - case Pf2: - case Pf3: - if(osize != 1){ - if(op != Pm) - *andptr++ = op; - *andptr++ = Pm; - op = o->op[++z]; - break; - } - default: - if(andptr == and || andptr[-1] != Pm) - *andptr++ = Pm; - break; - } - *andptr++ = op; - return z; -} - -void -doasm(Prog *p) -{ - Optab *o; - Prog *q, pp; - uchar *t; - int z, op, ft, tt, breg; - int32 v, pre; - Reloc rel, *r; - Adr *a; - - curp = p; // TODO - - 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); - if(p->tt == 0) - p->tt = oclass(&p->to); - - ft = p->ft * Ymax; - tt = p->tt * Ymax; - o = &optab[p->as]; - t = o->ytab; - if(t == 0) { - diag("asmins: noproto %P", p); - return; - } - for(z=0; *t; z+=t[3],t+=4) - if(ycover[ft+t[0]]) - if(ycover[tt+t[1]]) - goto found; - goto domov; - -found: - switch(o->prefix) { - case Pq: /* 16 bit escape and opcode escape */ - *andptr++ = Pe; - *andptr++ = Pm; - break; - - case Pf2: /* xmm opcode escape */ - case Pf3: - *andptr++ = o->prefix; - *andptr++ = Pm; - break; - - case Pm: /* opcode escape */ - *andptr++ = Pm; - break; - - case Pe: /* 16 bit escape */ - *andptr++ = Pe; - break; - - case Pb: /* botch */ - break; - } - - op = o->op[z]; - switch(t[2]) { - default: - diag("asmins: unknown z %d %P", t[2], p); - return; - - case Zpseudo: - break; - - case Zlit: - for(; op = o->op[z]; z++) - *andptr++ = op; - break; - - case Zlitm_r: - for(; op = o->op[z]; z++) - *andptr++ = op; - asmand(&p->from, reg[p->to.type]); - break; - - case Zm_r: - *andptr++ = op; - asmand(&p->from, reg[p->to.type]); - break; - - case Zm2_r: - *andptr++ = op; - *andptr++ = o->op[z+1]; - asmand(&p->from, reg[p->to.type]); - break; - - case Zm_r_xm: - mediaop(o, op, t[3], z); - asmand(&p->from, reg[p->to.type]); - break; - - case Zm_r_i_xm: - mediaop(o, op, t[3], z); - asmand(&p->from, reg[p->to.type]); - *andptr++ = p->to.offset; - break; - - case Zibm_r: - while ((op = o->op[z++]) != 0) - *andptr++ = op; - asmand(&p->from, reg[p->to.type]); - *andptr++ = p->to.offset; - break; - - case Zaut_r: - *andptr++ = 0x8d; /* leal */ - if(p->from.type != D_ADDR) - diag("asmins: Zaut sb type ADDR"); - p->from.type = p->from.index; - p->from.index = D_NONE; - p->ft = 0; - asmand(&p->from, reg[p->to.type]); - p->from.index = p->from.type; - p->from.type = D_ADDR; - p->ft = 0; - break; - - case Zm_o: - *andptr++ = op; - asmand(&p->from, o->op[z+1]); - break; - - case Zr_m: - *andptr++ = op; - asmand(&p->to, reg[p->from.type]); - break; - - case Zr_m_xm: - mediaop(o, op, t[3], z); - asmand(&p->to, reg[p->from.type]); - break; - - case Zr_m_i_xm: - mediaop(o, op, t[3], z); - asmand(&p->to, reg[p->from.type]); - *andptr++ = p->from.offset; - break; - - case Zo_m: - *andptr++ = op; - asmand(&p->to, o->op[z+1]); - break; - - case Zm_ibo: - *andptr++ = op; - asmand(&p->from, o->op[z+1]); - *andptr++ = vaddr(&p->to, nil); - break; - - case Zibo_m: - *andptr++ = op; - asmand(&p->to, o->op[z+1]); - *andptr++ = vaddr(&p->from, nil); - break; - - case Z_ib: - case Zib_: - 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++ = 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 - relput4(p, &p->from); - break; - - case Zib_rr: - *andptr++ = op; - asmand(&p->to, reg[p->to.type]); - *andptr++ = vaddr(&p->from, nil); - break; - - case Z_il: - case Zil_: - if(t[2] == Zil_) - a = &p->from; - else - a = &p->to; - *andptr++ = op; - if(o->prefix == Pe) { - v = vaddr(a, nil); - *andptr++ = v; - *andptr++ = v>>8; - } - else - relput4(p, a); - break; - - case Zm_ilo: - case Zilo_m: - *andptr++ = op; - 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 - 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 - relput4(p, &p->from); - break; - - case Z_rp: - *andptr++ = op + reg[p->to.type]; - break; - - case Zrp_: - *andptr++ = op + reg[p->from.type]; - break; - - case Zclr: - *andptr++ = op; - asmand(&p->to, reg[p->to.type]); - break; - - case Zcall: - q = p->pcond; - 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->type = D_PCREL; - r->siz = 4; - r->sym = q->from.sym; - put4(0); - break; - - case Zbr: - case Zjmp: - case Zloop: - q = p->pcond; - if(q == nil) { - diag("jmp/branch/loop 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) { - if(p->as == AJCXZW) - *andptr++ = 0x67; - *andptr++ = op; - *andptr++ = v; - } else if(t[2] == Zloop) { - diag("loop too far: %P", p); - } 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 - if(p->as == AJCXZW) - *andptr++ = 0x67; - *andptr++ = op; - *andptr++ = 0; - } else if(t[2] == Zloop) { - diag("loop too far: %P", p); - } 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: - 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 Zcallind: - *andptr++ = op; - *andptr++ = o->op[z+1]; - r = addrel(cursym); - r->off = p->pc + andptr - and; - r->type = D_ADDR; - r->siz = 4; - r->add = p->to.offset; - r->sym = p->to.sym; - put4(0); - 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; - if(op > 2) { - *andptr++ = v>>16; - *andptr++ = v>>24; - } - } - break; - - case Zmov: - goto domov; - } - return; - -domov: - for(t=ymovtab; *t; t+=8) - if(p->as == t[0]) - if(ycover[ft+t[1]]) - if(ycover[tt+t[2]]) - goto mfound; -bad: - /* - * here, the assembly has failed. - * if its a byte instruction that has - * unaddressable registers, try to - * exchange registers and reissue the - * instruction with the operands renamed. - */ - pp = *p; - z = p->from.type; - if(z >= D_BP && z <= D_DI) { - if((breg = byteswapreg(&p->to)) != D_AX) { - *andptr++ = 0x87; /* xchg lhs,bx */ - asmand(&p->from, reg[breg]); - subreg(&pp, z, breg); - doasm(&pp); - *andptr++ = 0x87; /* xchg lhs,bx */ - asmand(&p->from, reg[breg]); - } else { - *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */ - subreg(&pp, z, D_AX); - doasm(&pp); - *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */ - } - return; - } - z = p->to.type; - if(z >= D_BP && z <= D_DI) { - if((breg = byteswapreg(&p->from)) != D_AX) { - *andptr++ = 0x87; /* xchg rhs,bx */ - asmand(&p->to, reg[breg]); - subreg(&pp, z, breg); - doasm(&pp); - *andptr++ = 0x87; /* xchg rhs,bx */ - asmand(&p->to, reg[breg]); - } else { - *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */ - subreg(&pp, z, D_AX); - doasm(&pp); - *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */ - } - return; - } - diag("doasm: notfound t2=%ux from=%ux to=%ux %P", t[2], p->from.type, p->to.type, p); - return; - -mfound: - switch(t[3]) { - default: - diag("asmins: unknown mov %d %P", t[3], p); - break; - - case 0: /* lit */ - for(z=4; t[z]!=E; z++) - *andptr++ = t[z]; - break; - - case 1: /* r,m */ - *andptr++ = t[4]; - asmand(&p->to, t[5]); - break; - - case 2: /* m,r */ - *andptr++ = t[4]; - asmand(&p->from, t[5]); - break; - - case 3: /* r,m - 2op */ - *andptr++ = t[4]; - *andptr++ = t[5]; - asmand(&p->to, t[6]); - break; - - case 4: /* m,r - 2op */ - *andptr++ = t[4]; - *andptr++ = t[5]; - asmand(&p->from, t[6]); - break; - - case 5: /* load full pointer, trash heap */ - if(t[4]) - *andptr++ = t[4]; - switch(p->to.index) { - default: - goto bad; - case D_DS: - *andptr++ = 0xc5; - break; - case D_SS: - *andptr++ = 0x0f; - *andptr++ = 0xb2; - break; - case D_ES: - *andptr++ = 0xc4; - break; - case D_FS: - *andptr++ = 0x0f; - *andptr++ = 0xb4; - break; - case D_GS: - *andptr++ = 0x0f; - *andptr++ = 0xb5; - break; - } - asmand(&p->from, reg[p->to.type]); - break; - - case 6: /* double shift */ - z = p->from.type; - switch(z) { - default: - goto bad; - case D_CONST: - *andptr++ = 0x0f; - *andptr++ = t[4]; - asmand(&p->to, reg[p->from.index]); - *andptr++ = p->from.offset; - break; - case D_CL: - case D_CX: - *andptr++ = 0x0f; - *andptr++ = t[5]; - asmand(&p->to, reg[p->from.index]); - break; - } - break; - - case 7: /* imul rm,r */ - if(t[4] == Pq) { - *andptr++ = Pe; - *andptr++ = Pm; - } else - *andptr++ = t[4]; - *andptr++ = t[5]; - asmand(&p->from, reg[p->to.type]); - break; - } -} - -void -asmins(Prog *p) -{ - andptr = and; - doasm(p); - if(andptr > and+sizeof and) { - print("and[] is too short - %ld byte instruction\n", andptr - and); - errorexit(); - } -} diff --git a/src/cmd/addr2line/addr2line_test.go b/src/cmd/addr2line/addr2line_test.go new file mode 100644 index 000000000..b278d08ce --- /dev/null +++ b/src/cmd/addr2line/addr2line_test.go @@ -0,0 +1,115 @@ +// Copyright 2014 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 ( + "bufio" + "bytes" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + "testing" +) + +func loadSyms(t *testing.T) map[string]string { + cmd := exec.Command("go", "tool", "nm", os.Args[0]) + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("go tool nm %v: %v\n%s", os.Args[0], err, string(out)) + } + syms := make(map[string]string) + scanner := bufio.NewScanner(bytes.NewReader(out)) + for scanner.Scan() { + f := strings.Fields(scanner.Text()) + if len(f) < 3 { + continue + } + syms[f[2]] = f[0] + } + if err := scanner.Err(); err != nil { + t.Fatalf("error reading symbols: %v", err) + } + return syms +} + +func runAddr2Line(t *testing.T, exepath, addr string) (funcname, path, lineno string) { + cmd := exec.Command(exepath, os.Args[0]) + cmd.Stdin = strings.NewReader(addr) + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("go tool addr2line %v: %v\n%s", os.Args[0], err, string(out)) + } + f := strings.Split(string(out), "\n") + if len(f) < 3 && f[2] == "" { + t.Fatal("addr2line output must have 2 lines") + } + funcname = f[0] + pathAndLineNo := f[1] + f = strings.Split(pathAndLineNo, ":") + if runtime.GOOS == "windows" { + switch len(f) { + case 2: + return funcname, f[0], f[1] + case 3: + return funcname, f[0] + ":" + f[1], f[2] + default: + t.Fatalf("no line number found in %q", pathAndLineNo) + } + } + if len(f) != 2 { + t.Fatalf("no line number found in %q", pathAndLineNo) + } + return funcname, f[0], f[1] +} + +const symName = "cmd/addr2line.TestAddr2Line" + +func testAddr2Line(t *testing.T, exepath, addr string) { + funcName, srcPath, srcLineNo := runAddr2Line(t, exepath, addr) + if symName != funcName { + t.Fatalf("expected function name %v; got %v", symName, funcName) + } + fi1, err := os.Stat("addr2line_test.go") + if err != nil { + t.Fatalf("Stat failed: %v", err) + } + fi2, err := os.Stat(srcPath) + if err != nil { + t.Fatalf("Stat failed: %v", err) + } + if !os.SameFile(fi1, fi2) { + t.Fatalf("addr2line_test.go and %s are not same file", srcPath) + } + if srcLineNo != "94" { + t.Fatalf("line number = %v; want 94", srcLineNo) + } +} + +// This is line 93. The test depends on that. +func TestAddr2Line(t *testing.T) { + if runtime.GOOS == "nacl" { + t.Skip("skipping on nacl") + } + + syms := loadSyms(t) + + tmpDir, err := ioutil.TempDir("", "TestAddr2Line") + if err != nil { + t.Fatal("TempDir failed: ", err) + } + defer os.RemoveAll(tmpDir) + + exepath := filepath.Join(tmpDir, "testaddr2line.exe") + out, err := exec.Command("go", "build", "-o", exepath, "cmd/addr2line").CombinedOutput() + if err != nil { + t.Fatalf("go build -o %v cmd/addr2line: %v\n%s", exepath, err, string(out)) + } + + testAddr2Line(t, exepath, syms[symName]) + testAddr2Line(t, exepath, "0x"+syms[symName]) +} diff --git a/src/cmd/addr2line/main.c b/src/cmd/addr2line/main.c deleted file mode 100644 index 54c4d90b5..000000000 --- a/src/cmd/addr2line/main.c +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2012 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. - -/* - * addr2line simulation - only enough to make pprof work on Macs - */ - -#include -#include -#include -#include - -void -printusage(int fd) -{ - fprint(fd, "usage: addr2line binary\n"); - fprint(fd, "reads addresses from standard input and writes two lines for each:\n"); - fprint(fd, "\tfunction name\n"); - fprint(fd, "\tfile:line\n"); -} - -void -usage(void) -{ - printusage(2); - exits("usage"); -} - -void -main(int argc, char **argv) -{ - int fd; - char *p, *q; - uvlong pc; - Symbol s; - Fhdr fhdr; - Biobuf bin, bout; - char file[1024]; - - if(argc > 1 && strcmp(argv[1], "--help") == 0) { - printusage(1); - exits(0); - } - - ARGBEGIN{ - default: - usage(); - }ARGEND - - if(argc != 1) - usage(); - - fd = open(argv[0], OREAD); - if(fd < 0) - sysfatal("open %s: %r", argv[0]); - if(crackhdr(fd, &fhdr) <= 0) - sysfatal("crackhdr: %r"); - machbytype(fhdr.type); - if(syminit(fd, &fhdr) <= 0) - sysfatal("syminit: %r"); - - Binit(&bin, 0, OREAD); - Binit(&bout, 1, OWRITE); - for(;;) { - p = Brdline(&bin, '\n'); - if(p == nil) - break; - p[Blinelen(&bin)-1] = '\0'; - q = strchr(p, ':'); - if(q != nil) { - // reverse: translate file:line to pc - *q++ = '\0'; - pc = file2pc(p, atoi(q)); - if(pc == ~(uvlong)0) - Bprint(&bout, "!%r\n"); - else - Bprint(&bout, "0x%llux\n", pc); - continue; - } - pc = strtoull(p, 0, 16); - if(!findsym(pc, CTEXT, &s)) - s.name = "??"; - if(!fileline(file, sizeof file, pc)) - strcpy(file, "??:0"); - Bprint(&bout, "%s\n%s\n", s.name, file); - } - Bflush(&bout); - exits(0); -} diff --git a/src/cmd/addr2line/main.go b/src/cmd/addr2line/main.go new file mode 100644 index 000000000..b94ba12ef --- /dev/null +++ b/src/cmd/addr2line/main.go @@ -0,0 +1,253 @@ +// Copyright 2012 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. + +// Addr2line is a minimal simulation of the GNU addr2line tool, +// just enough to support pprof. +// +// Usage: +// go tool addr2line binary +// +// Addr2line reads hexadecimal addresses, one per line and with optional 0x prefix, +// from standard input. For each input address, addr2line prints two output lines, +// first the name of the function containing the address and second the file:line +// of the source code corresponding to that address. +// +// This tool is intended for use only by pprof; its interface may change or +// it may be deleted entirely in future releases. +package main + +import ( + "bufio" + "debug/elf" + "debug/gosym" + "debug/macho" + "debug/pe" + "debug/plan9obj" + "flag" + "fmt" + "log" + "os" + "strconv" + "strings" +) + +func printUsage(w *os.File) { + fmt.Fprintf(w, "usage: addr2line binary\n") + fmt.Fprintf(w, "reads addresses from standard input and writes two lines for each:\n") + fmt.Fprintf(w, "\tfunction name\n") + fmt.Fprintf(w, "\tfile:line\n") +} + +func usage() { + printUsage(os.Stderr) + os.Exit(2) +} + +func main() { + log.SetFlags(0) + log.SetPrefix("addr2line: ") + + // pprof expects this behavior when checking for addr2line + if len(os.Args) > 1 && os.Args[1] == "--help" { + printUsage(os.Stdout) + os.Exit(0) + } + + flag.Usage = usage + flag.Parse() + if flag.NArg() != 1 { + usage() + } + + f, err := os.Open(flag.Arg(0)) + if err != nil { + log.Fatal(err) + } + + textStart, symtab, pclntab, err := loadTables(f) + if err != nil { + log.Fatalf("reading %s: %v", flag.Arg(0), err) + } + + pcln := gosym.NewLineTable(pclntab, textStart) + tab, err := gosym.NewTable(symtab, pcln) + if err != nil { + log.Fatalf("reading %s: %v", flag.Arg(0), err) + } + + stdin := bufio.NewScanner(os.Stdin) + stdout := bufio.NewWriter(os.Stdout) + + for stdin.Scan() { + p := stdin.Text() + if strings.Contains(p, ":") { + // Reverse translate file:line to pc. + // This was an extension in the old C version of 'go tool addr2line' + // and is probably not used by anyone, but recognize the syntax. + // We don't have an implementation. + fmt.Fprintf(stdout, "!reverse translation not implemented\n") + continue + } + pc, _ := strconv.ParseUint(strings.TrimPrefix(p, "0x"), 16, 64) + file, line, fn := tab.PCToLine(pc) + name := "?" + if fn != nil { + name = fn.Name + } else { + file = "?" + line = 0 + } + fmt.Fprintf(stdout, "%s\n%s:%d\n", name, file, line) + } + stdout.Flush() +} + +func loadTables(f *os.File) (textStart uint64, symtab, pclntab []byte, err error) { + if obj, err := elf.NewFile(f); err == nil { + if sect := obj.Section(".text"); sect != nil { + textStart = sect.Addr + } + if sect := obj.Section(".gosymtab"); sect != nil { + if symtab, err = sect.Data(); err != nil { + return 0, nil, nil, err + } + } + if sect := obj.Section(".gopclntab"); sect != nil { + if pclntab, err = sect.Data(); err != nil { + return 0, nil, nil, err + } + } + return textStart, symtab, pclntab, nil + } + + if obj, err := macho.NewFile(f); err == nil { + if sect := obj.Section("__text"); sect != nil { + textStart = sect.Addr + } + if sect := obj.Section("__gosymtab"); sect != nil { + if symtab, err = sect.Data(); err != nil { + return 0, nil, nil, err + } + } + if sect := obj.Section("__gopclntab"); sect != nil { + if pclntab, err = sect.Data(); err != nil { + return 0, nil, nil, err + } + } + return textStart, symtab, pclntab, nil + } + + if obj, err := pe.NewFile(f); err == nil { + var imageBase uint64 + switch oh := obj.OptionalHeader.(type) { + case *pe.OptionalHeader32: + imageBase = uint64(oh.ImageBase) + case *pe.OptionalHeader64: + imageBase = oh.ImageBase + default: + return 0, nil, nil, fmt.Errorf("pe file format not recognized") + } + if sect := obj.Section(".text"); sect != nil { + textStart = imageBase + uint64(sect.VirtualAddress) + } + if pclntab, err = loadPETable(obj, "pclntab", "epclntab"); err != nil { + return 0, nil, nil, err + } + if symtab, err = loadPETable(obj, "symtab", "esymtab"); err != nil { + return 0, nil, nil, err + } + return textStart, symtab, pclntab, nil + } + + if obj, err := plan9obj.NewFile(f); err == nil { + sym, err := findPlan9Symbol(obj, "text") + if err != nil { + return 0, nil, nil, err + } + textStart = sym.Value + if pclntab, err = loadPlan9Table(obj, "pclntab", "epclntab"); err != nil { + return 0, nil, nil, err + } + if symtab, err = loadPlan9Table(obj, "symtab", "esymtab"); err != nil { + return 0, nil, nil, err + } + return textStart, symtab, pclntab, nil + } + + return 0, nil, nil, fmt.Errorf("unrecognized binary format") +} + +func findPESymbol(f *pe.File, name string) (*pe.Symbol, error) { + for _, s := range f.Symbols { + if s.Name != name { + continue + } + if s.SectionNumber <= 0 { + return nil, fmt.Errorf("symbol %s: invalid section number %d", name, s.SectionNumber) + } + if len(f.Sections) < int(s.SectionNumber) { + return nil, fmt.Errorf("symbol %s: section number %d is larger than max %d", name, s.SectionNumber, len(f.Sections)) + } + return s, nil + } + return nil, fmt.Errorf("no %s symbol found", name) +} + +func loadPETable(f *pe.File, sname, ename string) ([]byte, error) { + ssym, err := findPESymbol(f, sname) + if err != nil { + return nil, err + } + esym, err := findPESymbol(f, ename) + if err != nil { + return nil, err + } + if ssym.SectionNumber != esym.SectionNumber { + return nil, fmt.Errorf("%s and %s symbols must be in the same section", sname, ename) + } + sect := f.Sections[ssym.SectionNumber-1] + data, err := sect.Data() + if err != nil { + return nil, err + } + return data[ssym.Value:esym.Value], nil +} + +func findPlan9Symbol(f *plan9obj.File, name string) (*plan9obj.Sym, error) { + syms, err := f.Symbols() + if err != nil { + return nil, err + } + for _, s := range syms { + if s.Name != name { + continue + } + return &s, nil + } + return nil, fmt.Errorf("no %s symbol found", name) +} + +func loadPlan9Table(f *plan9obj.File, sname, ename string) ([]byte, error) { + ssym, err := findPlan9Symbol(f, sname) + if err != nil { + return nil, err + } + esym, err := findPlan9Symbol(f, ename) + if err != nil { + return nil, err + } + text, err := findPlan9Symbol(f, "text") + if err != nil { + return nil, err + } + sect := f.Section("text") + if sect == nil { + return nil, err + } + data, err := sect.Data() + if err != nil { + return nil, err + } + return data[ssym.Value-text.Value : esym.Value-text.Value], nil +} diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go index a62c87421..4bde794a1 100644 --- a/src/cmd/api/goapi.go +++ b/src/cmd/api/goapi.go @@ -817,7 +817,7 @@ func (w *Walker) emitFunc(f *types.Func) { func (w *Walker) emitMethod(m *types.Selection) { sig := m.Type().(*types.Signature) recv := sig.Recv().Type() - // report exported methods with unexported reveiver base type + // report exported methods with unexported receiver base type if true { base := recv if p, _ := recv.(*types.Pointer); p != nil { diff --git a/src/cmd/api/run.go b/src/cmd/api/run.go index 1e10dc600..896b2b4a1 100644 --- a/src/cmd/api/run.go +++ b/src/cmd/api/run.go @@ -46,14 +46,14 @@ func main() { gopath := prepGoPath() cmd := exec.Command("go", "install", "--tags=api_tool", "cmd/api") - cmd.Env = append([]string{"GOPATH=" + gopath}, filterOut(os.Environ(), "GOARCH")...) + cmd.Env = append(filterOut(os.Environ(), "GOARCH", "GOPATH"), "GOPATH="+gopath) out, err := cmd.CombinedOutput() if err != nil { log.Fatalf("Error installing cmd/api: %v\n%s", err, out) } out, err = exec.Command("go", "tool", "api", - "-c", file("go1", "go1.1", "go1.2"), + "-c", file("go1", "go1.1", "go1.2", "go1.3"), "-next", file("next"), "-except", file("except")).CombinedOutput() if err != nil { diff --git a/src/cmd/cc/cc.h b/src/cmd/cc/cc.h index af2339c97..c8aac1253 100644 --- a/src/cmd/cc/cc.h +++ b/src/cmd/cc/cc.h @@ -30,6 +30,7 @@ #include #include +#include #ifndef EXTERN #define EXTERN extern @@ -48,13 +49,13 @@ typedef struct Type Type; typedef struct Funct Funct; typedef struct Decl Decl; typedef struct Io Io; -typedef struct Hist Hist; typedef struct Term Term; typedef struct Init Init; typedef struct Bits Bits; typedef struct Bvec Bvec; typedef struct Dynimp Dynimp; typedef struct Dynexp Dynexp; +typedef struct Var Var; typedef Rune TRune; /* target system type */ @@ -83,6 +84,14 @@ struct Bvec uint32 b[]; }; +struct Var +{ + vlong offset; + LSym* sym; + char name; + char etype; +}; + struct Node { Node* left; @@ -114,6 +123,7 @@ struct Node struct Sym { Sym* link; + LSym* lsym; Type* type; Type* suetag; Type* tenum; @@ -200,16 +210,6 @@ struct Io }; #define I ((Io*)0) -struct Hist -{ - Hist* link; - char* name; - int32 line; - int32 offset; -}; -#define H ((Hist*)0) -EXTERN Hist* hist; - struct Term { vlong mult; @@ -469,7 +469,6 @@ EXTERN int32 autoffset; EXTERN int blockno; EXTERN Decl* dclstack; EXTERN int debug[256]; -EXTERN Hist* ehist; EXTERN int32 firstbit; EXTERN Sym* firstarg; EXTERN Type* firstargtype; @@ -498,7 +497,6 @@ EXTERN int32 nsymb; EXTERN Biobuf outbuf; EXTERN Biobuf diagbuf; EXTERN char* outfile; -EXTERN char* pathname; EXTERN int peekc; EXTERN int32 stkoff; EXTERN Type* strf; @@ -508,8 +506,9 @@ EXTERN Sym* symstring; EXTERN int taggen; EXTERN Type* tfield; EXTERN Type* tufield; -EXTERN int thechar; -EXTERN char* thestring; +extern int thechar; +extern char* thestring; +extern LinkArch* thelinkarch; EXTERN Type* thisfn; EXTERN int32 thunk; EXTERN Type* types[NALLTYPES]; @@ -525,8 +524,11 @@ EXTERN int flag_largemodel; EXTERN int ncontin; EXTERN int canreach; EXTERN int warnreach; +EXTERN int nacl; EXTERN Bits zbits; EXTERN Fmt pragcgobuf; +EXTERN Biobuf bstdout; +EXTERN Var var[NVAR]; extern char *onames[], *tnames[], *gnames[]; extern char *cnames[], *qnames[], *bnames[]; @@ -556,6 +558,7 @@ extern uchar typechlpfd[]; EXTERN uchar* typeword; EXTERN uchar* typecmplx; +EXTERN Link* ctxt; extern uint32 thash1; extern uint32 thash2; @@ -603,6 +606,7 @@ int FNconv(Fmt*); int Oconv(Fmt*); int Qconv(Fmt*); int VBconv(Fmt*); +int Bconv(Fmt*); void setinclude(char*); /* @@ -612,7 +616,6 @@ void dodefine(char*); void domacro(void); Sym* getsym(void); int32 getnsn(void); -void linehist(char*, int); void macdef(void); void macprag(void); void macend(void); @@ -731,6 +734,7 @@ void diag(Node*, char*, ...); void warn(Node*, char*, ...); void yyerror(char*, ...); void fatal(Node*, char*, ...); +LSym* linksym(Sym*); /* * acid.c @@ -791,6 +795,7 @@ int32 exreg(Type*); int32 align(int32, Type*, int, int32*); int32 maxround(int32, int32); int hasdotdotdot(void); +void linkarchinit(void); extern schar ewidth[]; @@ -814,6 +819,7 @@ int machcap(Node*); #pragma varargck argpos diag 2 #pragma varargck argpos yyerror 1 +#pragma varargck type "B" Bits #pragma varargck type "F" Node* #pragma varargck type "L" int32 #pragma varargck type "Q" int32 diff --git a/src/cmd/cc/lex.c b/src/cmd/cc/lex.c index 049dc5196..424843764 100644 --- a/src/cmd/cc/lex.c +++ b/src/cmd/cc/lex.c @@ -117,8 +117,28 @@ void main(int argc, char *argv[]) { int c; + char *p; + + // Allow GOARCH=thestring or GOARCH=thestringsuffix, + // but not other values. + p = getgoarch(); + if(strncmp(p, thestring, strlen(thestring)) != 0) + sysfatal("cannot use %cc with GOARCH=%s", thechar, p); + if(strcmp(p, "amd64p32") == 0) // must be before cinit + ewidth[TIND] = 4; + + nacl = strcmp(getgoos(), "nacl") == 0; + if(nacl) + flag_largemodel = 1; quotefmtinstall(); // before cinit, which overrides %Q + + linkarchinit(); + ctxt = linknew(thelinkarch); + ctxt->diag = yyerror; + ctxt->bso = &bstdout; + Binit(&bstdout, 1, OWRITE); + ensuresymb(NSYMB); memset(debug, 0, sizeof(debug)); tinit(); @@ -175,12 +195,14 @@ main(int argc, char *argv[]) flagcount("q", "print Go definitions", &debug['q']); flagcount("s", "print #define assembly offsets", &debug['s']); flagcount("t", "debug code generation", &debug['t']); + flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath); flagcount("w", "enable warnings", &debug['w']); flagcount("v", "increase debug verbosity", &debug['v']); if(thechar == '6') flagcount("largemodel", "generate code that assumes a large memory model", &flag_largemodel); flagparse(&argc, &argv, usage); + ctxt->debugasm = debug['S']; if(argc < 1 && outfile == 0) usage(); @@ -195,6 +217,7 @@ main(int argc, char *argv[]) else c = compile(argv[0], defs, ndef); + Bflush(&bstdout); if(c) errorexit(); exits(0); @@ -331,6 +354,7 @@ compile(char *file, char **defs, int ndef) void errorexit(void) { + Bflush(&bstdout); if(outfile) remove(outfile); exits("error"); @@ -390,7 +414,7 @@ newfile(char *s, int f) errorexit(); } fi.c = 0; - linehist(s, 0); + linklinehist(ctxt, lineno, s, 0); } Sym* @@ -1300,13 +1324,6 @@ cinit(void) nodproto = new(OPROTO, Z, Z); dclstack = D; - pathname = allocn(pathname, 0, 100); - if(getwd(pathname, 99) == 0) { - pathname = allocn(pathname, 100, 900); - if(getwd(pathname, 999) == 0) - strcpy(pathname, "/???"); - } - fmtinstall('O', Oconv); fmtinstall('T', Tconv); fmtinstall('F', FNconv); @@ -1314,6 +1331,7 @@ cinit(void) fmtinstall('Q', Qconv); fmtinstall('|', VBconv); fmtinstall('U', Uconv); + fmtinstall('B', Bconv); } int @@ -1330,7 +1348,7 @@ loop: fi.c = read(i->f, i->b, BUFSIZ) - 1; if(fi.c < 0) { close(i->f); - linehist(0, 0); + linklinehist(ctxt, lineno, nil, 0); goto pop; } fi.p = i->b + 1; @@ -1365,70 +1383,7 @@ Oconv(Fmt *fp) int Lconv(Fmt *fp) { - char str[STRINGSZ], s[STRINGSZ]; - Hist *h; - struct - { - Hist* incl; /* start of this include file */ - int32 idel; /* delta line number to apply to include */ - Hist* line; /* start of this #line directive */ - int32 ldel; /* delta line number to apply to #line */ - } a[HISTSZ]; - int32 l, d; - int i, n; - - l = va_arg(fp->args, int32); - n = 0; - for(h = hist; h != H; h = h->link) { - if(l < h->line) - break; - if(h->name) { - if(h->offset != 0) { /* #line directive, not #pragma */ - if(n > 0 && n < HISTSZ && h->offset >= 0) { - a[n-1].line = h; - a[n-1].ldel = h->line - h->offset + 1; - } - } else { - if(n < HISTSZ) { /* beginning of file */ - a[n].incl = h; - a[n].idel = h->line; - a[n].line = 0; - } - n++; - } - continue; - } - n--; - if(n > 0 && n < HISTSZ) { - d = h->line - a[n].incl->line; - a[n-1].ldel += d; - a[n-1].idel += d; - } - } - if(n > HISTSZ) - n = HISTSZ; - str[0] = 0; - for(i=n-1; i>=0; i--) { - if(i != n-1) { - if(fp->flags & ~(FmtWidth|FmtPrec)) /* BUG ROB - was f3 */ - break; - strcat(str, " "); - } - if(a[i].line) - 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:%d", - a[i].incl->name, l-a[i].idel+1); - if(strlen(s)+strlen(str) >= STRINGSZ-10) - break; - strcat(str, s); - l = a[i].incl->line - 1; /* now print out start of this file */ - } - if(n == 0) - strcat(str, ""); - return fmtstrcpy(fp, str); + return linklinefmt(ctxt, fp); } int @@ -1548,6 +1503,32 @@ VBconv(Fmt *fp) return fmtstrcpy(fp, str); } +int +Bconv(Fmt *fp) +{ + char str[STRINGSZ], ss[STRINGSZ], *s; + Bits bits; + int i; + + str[0] = 0; + bits = va_arg(fp->args, Bits); + while(bany(&bits)) { + i = bnum(bits); + if(str[0]) + strcat(str, " "); + if(var[i].sym == nil) { + sprint(ss, "$%lld", var[i].offset); + s = ss; + } else + s = var[i].sym->name; + if(strlen(str) + strlen(s) + 1 >= STRINGSZ) + break; + strcat(str, s); + bits.b[i/32] &= ~(1L << (i%32)); + } + return fmtstrcpy(fp, str); +} + void setinclude(char *p) { diff --git a/src/cmd/cc/lexbody b/src/cmd/cc/lexbody index 9d293b089..e24db1bc0 100644 --- a/src/cmd/cc/lexbody +++ b/src/cmd/cc/lexbody @@ -152,7 +152,7 @@ setinclude(char *p) void errorexit(void) { - + Bflush(&bstdout); if(outfile) remove(outfile); exits("error"); @@ -209,7 +209,7 @@ newfile(char *s, int f) errorexit(); } fi.c = 0; - linehist(s, 0); + linklinehist(ctxt, lineno, s, 0); } Sym* @@ -477,7 +477,7 @@ l1: return LCONST; case '"': - memcpy(yylval.sval, nullgen.sval, sizeof(yylval.sval)); + memcpy(yylval.sval, nullgen.u.sval, sizeof(yylval.sval)); cp = yylval.sval; c1 = 0; for(;;) { @@ -638,10 +638,6 @@ pinit(char *f) pc = 0; peekc = IGN; sym = 1; - for(i=0; ilink) s->macro = 0; @@ -661,7 +657,7 @@ loop: fi.c = read(i->f, i->b, BUFSIZ) - 1; if(fi.c < 0) { close(i->f); - linehist(0, 0); + linklinehist(ctxt, lineno, 0, 0); goto pop; } fi.p = i->b + 1; @@ -709,67 +705,5 @@ yyerror(char *a, ...) void prfile(int32 l) { - int i, n; - Hist a[HISTSZ], *h; - int32 d; - - n = 0; - for(h = hist; h != H; h = h->link) { - if(l < h->line) - break; - if(h->name) { - if(h->offset == 0) { - if(n >= 0 && n < HISTSZ) - a[n] = *h; - n++; - continue; - } - if(n > 0 && n < HISTSZ) - if(a[n-1].offset == 0) { - a[n] = *h; - n++; - } else - a[n-1] = *h; - continue; - } - n--; - if(n >= 0 && n < HISTSZ) { - d = h->line - a[n].line; - for(i=0; i HISTSZ) - n = HISTSZ; - for(i=0; ih |= 0x80000000L; - return; - } - if(native == 0) { - ieee->l = 0; - ieee->h = 0; - return; - } - fr = frexp(native, &exp); - f = 2097152L; /* shouldn't use fp constants here */ - fr = modf(fr*f, &ho); - ieee->h = ho; - ieee->h &= 0xfffffL; - ieee->h |= (exp+1022L) << 20; - f = 65536L; - fr = modf(fr*f, &ho); - ieee->l = ho; - ieee->l = (uint32)ieee->l << 16; - ieee->l |= (int32)(fr*f); + linkprfile(ctxt, l); } diff --git a/src/cmd/cc/macbody b/src/cmd/cc/macbody index f0a507669..f6927b2f6 100644 --- a/src/cmd/cc/macbody +++ b/src/cmd/cc/macbody @@ -642,7 +642,7 @@ nn: c = strlen(symb) + 1; cp = alloc(c); memcpy(cp, symb, c); - linehist(cp, n); + linklinehist(ctxt, lineno, cp, n); return; bad: @@ -713,7 +713,6 @@ macprag(void) Sym *s; int c0, c; char *hp; - Hist *h; s = getsym(); @@ -779,18 +778,7 @@ praglib: hp = alloc(c); memcpy(hp, symb, c); - h = alloc(sizeof(Hist)); - h->name = hp; - h->line = lineno; - h->offset = -1; - h->link = H; - if(ehist == H) { - hist = h; - ehist = h; - return; - } - ehist->link = h; - ehist = h; + linklinehist(ctxt, lineno, hp, -1); return; bad: @@ -810,43 +798,3 @@ macend(void) return; } } - -void -linehist(char *f, int offset) -{ - Hist *h; - - /* - * overwrite the last #line directive if - * no alloc has happened since the last one - */ - if(newflag == 0 && ehist != H && offset != 0 && ehist->offset != 0) - if(f && ehist->name && strcmp(f, ehist->name) == 0) { - ehist->line = lineno; - ehist->offset = offset; - return; - } - - if(debug['f']) - if(f) { - if(offset) - print("%4d: %s (#line %d)\n", lineno, f, offset); - else - print("%4d: %s\n", lineno, f); - } else - print("%4d: \n", lineno); - newflag = 0; - - h = alloc(sizeof(Hist)); - h->name = f; - h->line = lineno; - h->offset = offset; - h->link = H; - if(ehist == H) { - hist = h; - ehist = h; - return; - } - ehist->link = h; - ehist = h; -} diff --git a/src/cmd/cc/pgen.c b/src/cmd/cc/pgen.c index b82872bc5..10bebc196 100644 --- a/src/cmd/cc/pgen.c +++ b/src/cmd/cc/pgen.c @@ -35,6 +35,26 @@ enum { BitsPerPointer = 2 }; static void dumpgcargs(Type *fn, Sym *sym); +static Sym* +makefuncdatasym(char *namefmt, int64 funcdatakind) +{ + Node nod; + Sym *sym; + static int32 nsym; + static char namebuf[40]; + + snprint(namebuf, sizeof(namebuf), namefmt, nsym++); + sym = slookup(namebuf); + sym->class = CSTATIC; + memset(&nod, 0, sizeof nod); + nod.op = ONAME; + nod.sym = sym; + nod.class = CSTATIC; + gins(AFUNCDATA, nodconst(funcdatakind), &nod); + linksym(sym)->type = SRODATA; + return sym; +} + int hasdotdotdot(void) { @@ -80,10 +100,10 @@ void codgen(Node *n, Node *nn) { Prog *sp; - Node *n1, nod, nod1, nod2; - Sym *gcsym, *gclocalssym; - static int ngcsym, ngclocalssym; - static char namebuf[40]; + Node *n1, nod, nod1; + Sym *gcargs; + Sym *gclocals; + int isvarargs; cursafe = 0; curarg = 0; @@ -109,25 +129,11 @@ codgen(Node *n, Node *nn) * generate funcdata symbol for this function. * data is filled in at the end of codgen(). */ - snprint(namebuf, sizeof namebuf, "gc·%d", ngcsym++); - gcsym = slookup(namebuf); - gcsym->class = CSTATIC; - - memset(&nod, 0, sizeof nod); - nod.op = ONAME; - nod.sym = gcsym; - nod.class = CSTATIC; - gins(AFUNCDATA, nodconst(FUNCDATA_GCArgs), &nod); - - snprint(namebuf, sizeof(namebuf), "gclocalssym·%d", ngclocalssym++); - gclocalssym = slookup(namebuf); - gclocalssym->class = CSTATIC; - - memset(&nod2, 0, sizeof(nod2)); - nod2.op = ONAME; - nod2.sym = gclocalssym; - nod2.class = CSTATIC; - gins(AFUNCDATA, nodconst(FUNCDATA_GCLocals), &nod2); + isvarargs = hasdotdotdot(); + gcargs = nil; + if(!isvarargs) + gcargs = makefuncdatasym("gcargs·%d", FUNCDATA_ArgsPointerMaps); + gclocals = makefuncdatasym("gclocals·%d", FUNCDATA_LocalsPointerMaps); /* * isolate first argument @@ -166,7 +172,8 @@ codgen(Node *n, Node *nn) maxargsafe = xround(maxargsafe, 8); sp->to.offset += maxargsafe; - dumpgcargs(thisfn, gcsym); + if(!isvarargs) + dumpgcargs(thisfn, gcargs); // TODO(rsc): "stkoff" is not right. It does not account for // the possibility of data stored in .safe variables. @@ -177,9 +184,9 @@ codgen(Node *n, Node *nn) // area its own section. // That said, we've been using stkoff for months // and nothing too terrible has happened. - gextern(gclocalssym, nodconst(-stkoff), 0, 4); // locals - gclocalssym->type = typ(0, T); - gclocalssym->type->width = 4; + gextern(gclocals, nodconst(-stkoff), 0, 4); // locals + gclocals->type = typ(0, T); + gclocals->type->width = 4; } void @@ -655,7 +662,9 @@ walktype1(Type *t, int32 offset, Bvec *bv, int param) { Type *t1; int32 o; + int32 widthptr; + widthptr = ewidth[TIND]; switch(t->etype) { case TCHAR: case TUCHAR: @@ -670,14 +679,16 @@ walktype1(Type *t, int32 offset, Bvec *bv, int param) case TFLOAT: case TDOUBLE: // non-pointer types + for(o = 0; o < t->width; o++) + bvset(bv, ((offset + t->offset + o) / widthptr) * BitsPerPointer); // 1 = live scalar break; case TIND: pointer: // pointer types - if((offset + t->offset) % ewidth[TIND] != 0) + if((offset + t->offset) % widthptr != 0) yyerror("unaligned pointer"); - bvset(bv, ((offset + t->offset) / ewidth[TIND])*BitsPerPointer); + bvset(bv, ((offset + t->offset) / widthptr)*BitsPerPointer + 1); // 2 = live ptr break; case TARRAY: @@ -715,39 +726,39 @@ dumpgcargs(Type *fn, Sym *sym) int32 argbytes; int32 symoffset, argoffset; - if(hasdotdotdot()) { - // give up for C vararg functions. - // TODO: maybe make a map just for the args we do know? - gextern(sym, nodconst(0), 0, 4); // nptrs=0 - symoffset = 4; - } else { - argbytes = (argsize() + ewidth[TIND] - 1); - bv = bvalloc((argbytes / ewidth[TIND]) * BitsPerPointer); - argoffset = align(0, fn->link, Aarg0, nil); - if(argoffset > 0) { - // The C calling convention returns structs by - // copying them to a location pointed to by a - // hidden first argument. This first argument - // is a pointer. - if(argoffset != ewidth[TIND]) - yyerror("passbyptr arg not the right size"); - bvset(bv, 0); - } - for(t = fn->down; t != T; t = t->down) { - if(t->etype == TVOID) - continue; - argoffset = align(argoffset, t, Aarg1, nil); - walktype1(t, argoffset, bv, 1); - argoffset = align(argoffset, t, Aarg2, nil); - } - gextern(sym, nodconst(bv->n), 0, 4); - symoffset = 4; - for(i = 0; i < bv->n; i += 32) { - gextern(sym, nodconst(bv->b[i/32]), symoffset, 4); - symoffset += 4; - } - free(bv); + // Dump the length of the bitmap array. This value is always one for + // functions written in C. + symoffset = 0; + gextern(sym, nodconst(1), symoffset, 4); + symoffset += 4; + argbytes = (argsize() + ewidth[TIND] - 1); + bv = bvalloc((argbytes / ewidth[TIND]) * BitsPerPointer); + argoffset = align(0, fn->link, Aarg0, nil); + if(argoffset > 0) { + // The C calling convention returns structs by copying them to a + // location pointed to by a hidden first argument. This first + // argument is a pointer. + if(argoffset != ewidth[TIND]) + yyerror("passbyptr arg not the right size"); + bvset(bv, 1); // 2 = live ptr + } + for(t = fn->down; t != T; t = t->down) { + if(t->etype == TVOID) + continue; + argoffset = align(argoffset, t, Aarg1, nil); + walktype1(t, argoffset, bv, 1); + argoffset = align(argoffset, t, Aarg2, nil); + } + // Dump the length of the bitmap. + gextern(sym, nodconst(bv->n), symoffset, 4); + symoffset += 4; + // Dump the words of the bitmap. + for(i = 0; i < bv->n; i += 32) { + gextern(sym, nodconst(bv->b[i/32]), symoffset, 4); + symoffset += 4; } + free(bv); + // Finalize the gc symbol. sym->type = typ(0, T); sym->type->width = symoffset; } diff --git a/src/cmd/cc/pswt.c b/src/cmd/cc/pswt.c index cc9c22763..bae57c64d 100644 --- a/src/cmd/cc/pswt.c +++ b/src/cmd/cc/pswt.c @@ -138,32 +138,3 @@ nullwarn(Node *l, Node *r) if(r != Z) cgen(r, Z); } - -void -ieeedtod(Ieee *ieee, double native) -{ - double fr, ho, f; - int exp; - - if(native < 0) { - ieeedtod(ieee, -native); - ieee->h |= 0x80000000L; - return; - } - if(native == 0) { - ieee->l = 0; - ieee->h = 0; - return; - } - fr = frexp(native, &exp); - f = 2097152L; /* shouldn't use fp constants here */ - fr = modf(fr*f, &ho); - ieee->h = ho; - ieee->h &= 0xfffffL; - ieee->h |= (exp+1022L) << 20; - f = 65536L; - fr = modf(fr*f, &ho); - ieee->l = ho; - ieee->l <<= 16; - ieee->l |= (int32)(fr*f); -} diff --git a/src/cmd/cc/sub.c b/src/cmd/cc/sub.c index bed989102..94c11d021 100644 --- a/src/cmd/cc/sub.c +++ b/src/cmd/cc/sub.c @@ -2056,3 +2056,13 @@ mixedasop(Type *l, Type *r) { return !typefd[l->etype] && typefd[r->etype]; } + +LSym* +linksym(Sym *s) +{ + if(s == nil) + return nil; + if(s->lsym != nil) + return s->lsym; + return linklookup(ctxt, s->name, s->class == CSTATIC); +} diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go index 605bab6d2..69c7ce893 100644 --- a/src/cmd/cgo/doc.go +++ b/src/cmd/cgo/doc.go @@ -52,6 +52,14 @@ these directives. Package-specific flags should be set using the directives, not the environment variables, so that builds work in unmodified environments. +All the cgo CPPFLAGS and CFLAGS directives in a package are concatenated and +used to compile C files in that package. All the CPPFLAGS and CXXFLAGS +directives in a package are concatenated and used to compile C++ files in that +package. All the LDFLAGS directives in any package in the program are +concatenated and used at link time. All the pkg-config directives are +concatenated and sent to pkg-config simultaneously to add to each appropriate +set of command-line flags. + When the Go tool sees that one or more Go files use the special import "C", it will look for other non-Go files in the directory and compile them as part of the Go package. Any .c, .s, or .S files will be @@ -63,11 +71,26 @@ compilers may be changed by the CC and CXX environment variables, respectively; those environment variables may include command line options. +To enable cgo during cross compiling builds, set the CGO_ENABLED +environment variable to 1 when building the Go tools with make.bash. +Also, set CC_FOR_TARGET to the C cross compiler for the target. CC will +be used for compiling for the host. + +After the Go tools are built, when running the go command, CC_FOR_TARGET is +ignored. The value of CC_FOR_TARGET when running make.bash is the default +compiler. However, you can set the environment variable CC, not CC_FOR_TARGET, +to control the compiler when running the go tool. + +CXX_FOR_TARGET works in a similar way for C++ code. + Go references to C Within the Go file, C's struct 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. +C struct fields that cannot be expressed in Go, such as bit fields +or misaligned data, are omitted in the Go struct, replaced by +appropriate padding to reach the next field or the end of the struct. The standard C numeric types are available under the names C.char, C.schar (signed char), C.uchar (unsigned char), @@ -84,6 +107,11 @@ C's union types are represented as a Go byte array with the same length. Go structs cannot embed fields with C types. +Cgo translates C types into equivalent unexported Go types. +Because the translations are unexported, a Go package should not +expose C types in its exported API: a C type used in one Go package +is different from the same C type used in another. + Any C function (even void functions) may be called in a multiple assignment context to retrieve both the return value (if any) and the C errno variable as an error (use _ to skip the result value if the diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index 3e1837ebf..7a802102d 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -1197,12 +1197,12 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { return t case *dwarf.StructType: - if dt.ByteSize < 0 { // opaque struct - break - } // Convert to Go struct, being careful about alignment. // Have to give it a name to simulate C "struct foo" references. tag := dt.StructName + if dt.ByteSize < 0 && tag == "" { // opaque unnamed struct - should not be possible + break + } if tag == "" { tag = "__" + strconv.Itoa(tagGen) tagGen++ @@ -1212,6 +1212,16 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { name := c.Ident("_Ctype_" + dt.Kind + "_" + tag) t.Go = name // publish before recursive calls goIdent[name.Name] = name + if dt.ByteSize < 0 { + // Size calculation in c.Struct/c.Opaque will die with size=-1 (unknown), + // so execute the basic things that the struct case would do + // other than try to determine a Go representation. + tt := *t + tt.C = &TypeRepr{"%s %s", []interface{}{dt.Kind, tag}} + tt.Go = c.Ident("struct{}") + typedef[name.Name] = &tt + break + } switch dt.Kind { case "class", "union": t.Go = c.Opaque(t.Size) @@ -1259,13 +1269,33 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { sub := c.Type(dt.Type, pos) t.Size = sub.Size t.Align = sub.Align - if _, ok := typedef[name.Name]; !ok { + oldType := typedef[name.Name] + if oldType == nil { tt := *t tt.Go = sub.Go typedef[name.Name] = &tt } - if *godefs || *cdefs { + + // If sub.Go.Name is "_Ctype_struct_foo" or "_Ctype_union_foo" or "_Ctype_class_foo", + // use that as the Go form for this typedef too, so that the typedef will be interchangeable + // with the base type. + // In -godefs and -cdefs mode, do this for all typedefs. + if isStructUnionClass(sub.Go) || *godefs || *cdefs { t.Go = sub.Go + + if isStructUnionClass(sub.Go) { + // Use the typedef name for C code. + typedef[sub.Go.(*ast.Ident).Name].C = t.C + } + + // If we've seen this typedef before, and it + // was an anonymous struct/union/class before + // too, use the old definition. + // TODO: it would be safer to only do this if + // we verify that the types are the same. + if oldType != nil && isStructUnionClass(oldType.Go) { + t.Go = oldType.Go + } } case *dwarf.UcharType: @@ -1327,9 +1357,21 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { // be correct, so calling dtype.Size again will produce the correct value. t.Size = dtype.Size() if t.Size < 0 { - // Unsized types are [0]byte + // Unsized types are [0]byte, unless they're typedefs of other types + // or structs with tags. + // if so, use the name we've already defined. t.Size = 0 - t.Go = c.Opaque(0) + switch dt := dtype.(type) { + case *dwarf.TypedefType: + // ok + case *dwarf.StructType: + if dt.StructName != "" { + break + } + t.Go = c.Opaque(0) + default: + t.Go = c.Opaque(0) + } if t.C.Empty() { t.C.Set("void") } @@ -1344,6 +1386,19 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { return t } +// isStructUnionClass reports whether the type described by the Go syntax x +// is a struct, union, or class with a tag. +func isStructUnionClass(x ast.Expr) bool { + id, ok := x.(*ast.Ident) + if !ok { + return false + } + name := id.Name + return strings.HasPrefix(name, "_Ctype_struct_") || + strings.HasPrefix(name, "_Ctype_union_") || + strings.HasPrefix(name, "_Ctype_class_") +} + // FuncArg returns a Go type with the same memory layout as // dtype when used as the type of a C function argument. func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type { @@ -1496,7 +1551,7 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct t := c.Type(f.Type, pos) tgo := t.Go size := t.Size - + talign := t.Align if f.BitSize > 0 { if f.BitSize%8 != 0 { continue @@ -1509,8 +1564,17 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct name = "uint" } tgo = ast.NewIdent(name + fmt.Sprint(f.BitSize)) + talign = size } + if talign > 0 && f.ByteOffset%talign != 0 { + // Drop misaligned fields, the same way we drop integer bit fields. + // The goal is to make available what can be made available. + // Otherwise one bad and unneeded field in an otherwise okay struct + // makes the whole program not compile. Much of the time these + // structs are in system headers that cannot be corrected. + continue + } n := len(fld) fld = fld[0 : n+1] name := f.Name @@ -1525,8 +1589,8 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct buf.WriteString(" ") buf.WriteString(name) buf.WriteString("; ") - if t.Align > align { - align = t.Align + if talign > align { + align = talign } } if off < dt.ByteSize { diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 83ab95251..76c7247af 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -485,7 +485,7 @@ func (p *Package) writeOutput(f *File, srcfile string) { fgcc.Close() } -// fixGo convers the internal Name.Go field into the name we should show +// fixGo converts the internal Name.Go field into the name we should show // to users in error messages. There's only one for now: on input we rewrite // C.malloc into C._CMalloc, so change it back here. func fixGo(name string) string { @@ -529,15 +529,8 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) { } // We're trying to write a gcc struct that matches 6c/8c/5c's layout. // Use packed attribute to force no padding in this struct in case - // gcc has different packing requirements. For example, - // on 386 Windows, gcc wants to 8-align int64s, but 8c does not. - // Use __gcc_struct__ to work around http://gcc.gnu.org/PR52991 on x86, - // and http://golang.org/issue/5603. - extraAttr := "" - if !strings.Contains(p.gccBaseCmd()[0], "clang") && (goarch == "amd64" || goarch == "386") { - extraAttr = ", __gcc_struct__" - } - fmt.Fprintf(fgcc, "\t%s __attribute__((__packed__%v)) *a = v;\n", ctype, extraAttr) + // gcc has different packing requirements. + fmt.Fprintf(fgcc, "\t%s %v *a = v;\n", ctype, p.packedAttribute()) fmt.Fprintf(fgcc, "\t") if t := n.FuncType.Result; t != nil { fmt.Fprintf(fgcc, "a->r = ") @@ -618,6 +611,19 @@ func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) { fmt.Fprintf(fgcc, "\n") } +// packedAttribute returns host compiler struct attribute that will be +// used to match 6c/8c/5c's struct layout. For example, on 386 Windows, +// gcc wants to 8-align int64s, but 8c does not. +// Use __gcc_struct__ to work around http://gcc.gnu.org/PR52991 on x86, +// and http://golang.org/issue/5603. +func (p *Package) packedAttribute() string { + s := "__attribute__((__packed__" + if !strings.Contains(p.gccBaseCmd()[0], "clang") && (goarch == "amd64" || goarch == "386") { + s += ", __gcc_struct__" + } + return s + "))" +} + // 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) { @@ -727,7 +733,7 @@ func (p *Package) writeExports(fgo2, fc, fm *os.File) { fmt.Fprintf(fgcc, "extern void _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 __attribute__((packed)) a;\n", ctype) + fmt.Fprintf(fgcc, "\t%s %v a;\n", ctype, p.packedAttribute()) if gccResult != "void" && (len(fntype.Results.List) > 1 || len(fntype.Results.List[0].Names) > 1) { fmt.Fprintf(fgcc, "\t%s r;\n", gccResult) } @@ -874,10 +880,24 @@ func (p *Package) writeGccgoExports(fgo2, fc, fm *os.File) { fmt.Fprintf(cdeclBuf, ")") cParams := cdeclBuf.String() + // We need to use a name that will be exported by the + // Go code; otherwise gccgo will make it static and we + // will not be able to link against it from the C + // code. goName := "Cgoexp_" + exp.ExpName fmt.Fprintf(fgcch, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, goName) fmt.Fprint(fgcch, "\n") + // Use a #define so that the C code that includes + // cgo_export.h will be able to refer to the Go + // function using the expected name. + fmt.Fprintf(fgcch, "#define %s %s\n", exp.ExpName, goName) + + // Use a #undef in _cgo_export.c so that we ignore the + // #define from cgo_export.h, since here we are + // defining the real function. + fmt.Fprintf(fgcc, "#undef %s\n", exp.ExpName) + fmt.Fprint(fgcc, "\n") fmt.Fprintf(fgcc, "%s %s %s {\n", cRet, exp.ExpName, cParams) fmt.Fprint(fgcc, "\t") @@ -1219,7 +1239,10 @@ struct __go_string __go_byte_array_to_string(const void* p, intgo len); struct __go_open_array __go_string_to_byte_array (struct __go_string str); const char *_cgoPREFIX_Cfunc_CString(struct __go_string s) { - return strndup((const char*)s.__data, s.__length); + char *p = malloc(s.__length+1); + memmove(p, s.__data, s.__length); + p[s.__length] = 0; + return p; } struct __go_string _cgoPREFIX_Cfunc_GoString(char *p) { diff --git a/src/cmd/dist/a.h b/src/cmd/dist/a.h index 9de93180f..6222e5060 100644 --- a/src/cmd/dist/a.h +++ b/src/cmd/dist/a.h @@ -75,7 +75,8 @@ extern char *goroot_final; extern char *goextlinkenabled; extern char *goversion; extern char *defaultcc; -extern char *defaultcxx; +extern char *defaultcxxtarget; +extern char *defaultcctarget; extern char *workdir; extern char *tooldir; extern char *slash; @@ -93,7 +94,7 @@ void cmdversion(int, char**); // buildgc.c void gcopnames(char*, char*); -void mkenam(char*, char*); +void mkanames(char*, char*); // buildruntime.c void mkzasm(char*, char*); diff --git a/src/cmd/dist/arm.c b/src/cmd/dist/arm.c index dafc5c1c2..52a621c5d 100644 --- a/src/cmd/dist/arm.c +++ b/src/cmd/dist/arm.c @@ -17,16 +17,8 @@ static void useVFPv1(void); char * xgetgoarm(void) { -#if defined(__NetBSD__) || defined(__FreeBSD__) - // NetBSD has buggy support for VFPv2 (incorrect inexact, - // denormial, and NaN handling). When GOARM=6, some of our - // math tests fails on Raspberry Pi. - // Thus we return "5" here for safety, the user is free - // to override. - // Note: using GOARM=6 with cgo can trigger a kernel assertion - // failure and crash NetBSD/evbarm kernel. - // FreeBSD also have broken VFP support, so disable VFP also - // on FreeBSD. +#if defined(__FreeBSD__) + // FreeBSD has broken VFP support return "5"; #endif if(xtryexecfunc(useVFPv3)) diff --git a/src/cmd/dist/build.c b/src/cmd/dist/build.c index e6e5f0cf7..6884e0aae 100644 --- a/src/cmd/dist/build.c +++ b/src/cmd/dist/build.c @@ -27,22 +27,27 @@ char *gochar; char *goversion; char *slash; // / for unix, \ for windows char *defaultcc; -char *defaultcxx; +char *defaultcflags; +char *defaultldflags; +char *defaultcxxtarget; +char *defaultcctarget; bool rebuildall; bool defaultclang; static bool shouldbuild(char*, char*); static void copy(char*, char*, int); +static void dopack(char*, char*, char**, int); static char *findgoversion(void); // The known architecture letters. -static char *gochars = "568"; +static char *gochars = "5668"; // The known architectures. static char *okgoarch[] = { // same order as gochars "arm", "amd64", + "amd64p32", "386", }; @@ -51,7 +56,9 @@ static char *okgoos[] = { "darwin", "dragonfly", "linux", + "solaris", "freebsd", + "nacl", "netbsd", "openbsd", "plan9", @@ -164,14 +171,29 @@ init(void) } defaultcc = btake(&b); - xgetenv(&b, "CXX"); + xgetenv(&b, "CFLAGS"); + defaultcflags = btake(&b); + + xgetenv(&b, "LDFLAGS"); + defaultldflags = btake(&b); + + xgetenv(&b, "CC_FOR_TARGET"); if(b.len == 0) { - if(defaultclang) - bprintf(&b, "clang++"); - else - bprintf(&b, "g++"); + bprintf(&b, defaultcc); } - defaultcxx = btake(&b); + defaultcctarget = btake(&b); + + xgetenv(&b, "CXX_FOR_TARGET"); + if(b.len == 0) { + xgetenv(&b, "CXX"); + if(b.len == 0) { + if(defaultclang) + bprintf(&b, "clang++"); + else + bprintf(&b, "g++"); + } + } + defaultcxxtarget = btake(&b); xsetenv("GOROOT", goroot); xsetenv("GOARCH", goarch); @@ -268,9 +290,8 @@ findgoversion(void) p = tags.p[i]; if(streq(p, "+")) nrev++; - // NOTE: Can reenable the /* */ code when we want to - // start reporting versions named 'weekly' again. - if(/*hasprefix(p, "weekly.") ||*/ hasprefix(p, "go")) { + // Only show the beta tag for the exact revision. + if(hasprefix(p, "go") && (!contains(p, "beta") || nrev == 0)) { tag = xstrdup(p); // If this tag matches the current checkout // exactly (no "+" yet), don't show extra @@ -344,7 +365,8 @@ static char *oldtool[] = { // Unreleased directories (relative to $GOROOT) that should // not be in release branches. static char *unreleased[] = { - "src/cmd/prof", + "src/cmd/link", + "src/pkg/debug/goobj", "src/pkg/old", }; @@ -414,7 +436,7 @@ setup(void) } // For release, make sure excluded things are excluded. - if(hasprefix(goversion, "release.") || hasprefix(goversion, "go")) { + if(hasprefix(goversion, "release.") || (hasprefix(goversion, "go") && !contains(goversion, "beta"))) { for(i=0; i 1) - errprintf("skipping %s - does not exist\n", dir); - goto out; - } - // set up gcc command line on first run. if(gccargs.len == 0) { - bprintf(&b, "%s", defaultcc); + bprintf(&b, "%s %s", defaultcc, defaultcflags); splitfields(&gccargs, bstr(&b)); for(i=0; i 1) errprintf("generate %s\n", p); @@ -916,20 +953,6 @@ install(char *dir) goto nobuild; } - // The files generated by GNU Bison use macros that aren't - // supported by the Plan 9 compilers so we have to use the - // external preprocessor when compiling. - usecpp = 0; - if(streq(gohostos, "plan9")) { - for(i=0; i p) + p = q; + } + if(p == nil) + p = extra[i]; + bwritef(&bdst, "%-16.16s%-12d%-6d%-6d%-8o%-10d`\n", p, 0, 0, 0, 0644, b.len); + bwriteb(&bdst, &b); + if(b.len&1) { + c = 0; + bwrite(&bdst, &c, 1); + } + } + + writefile(&bdst, dst, 0); + + bfree(&b); + bfree(&bdst); +} + // buildorder records the order of builds for the 'go bootstrap' command. static char *buildorder[] = { "lib9", "libbio", - "libmach", + "liblink", "misc/pprof", - "cmd/addr2line", - "cmd/nm", - "cmd/objdump", - "cmd/pack", - "cmd/prof", - "cmd/cc", // must be before c "cmd/gc", // must be before g "cmd/%sl", // must be before a, c, g @@ -1323,17 +1376,12 @@ static char *cleantab[] = { "cmd/8c", "cmd/8g", "cmd/8l", - "cmd/addr2line", "cmd/cc", "cmd/gc", - "cmd/go", - "cmd/nm", - "cmd/objdump", - "cmd/pack", - "cmd/prof", + "cmd/go", "lib9", "libbio", - "libmach", + "liblink", "pkg/bufio", "pkg/bytes", "pkg/container/heap", @@ -1388,8 +1436,6 @@ clean(void) vinit(&dir); for(i=0; iname = token; - p->type = read_type(); p->next = nil; *pp = p; pp = &p->next; - size = type_size(p->type); - rnd = size; - if(rnd > structround) - rnd = structround; - if(offset%rnd) - offset += rnd - offset%rnd; - offset += size; + if(streq(token, "...")) { + p->type = xstrdup(""); + } else { + p->type = read_type(); + rnd = 0; + size = type_size(p->type, &rnd); + if(rnd > structround) + rnd = structround; + if(offset%rnd) + offset += rnd - offset%rnd; + offset += size; + } token = read_token_no_eof(); if (!streq(token, ",")) @@ -418,7 +441,7 @@ read_params(int *poffset) } } if (!streq(token, ")")) { - fatal("%s:%ud: expected '('\n", + fatal("%s:%d: expected '('\n", file, lineno); } if (poffset != nil) @@ -438,6 +461,7 @@ read_func_header(char **name, struct params **params, int *paramwid, struct para lastline = -1; while (1) { + read_preprocessor_lines(); token = read_token(); if (token == nil) return 0; @@ -460,7 +484,7 @@ read_func_header(char **name, struct params **params, int *paramwid, struct para token = read_token(); if (token == nil || !streq(token, "(")) { - fatal("%s:%ud: expected \"(\"\n", + fatal("%s:%d: expected \"(\"\n", file, lineno); } *params = read_params(paramwid); @@ -473,7 +497,7 @@ read_func_header(char **name, struct params **params, int *paramwid, struct para token = read_token(); } if (token == nil || !streq(token, "{")) { - fatal("%s:%ud: expected \"{\"\n", + fatal("%s:%d: expected \"{\"\n", file, lineno); } return 1; @@ -500,8 +524,13 @@ write_6g_func_header(char *package, char *name, struct params *params, int paramwid, struct params *rets) { int first, n; + struct params *p; + + bwritef(output, "void\n"); + if(!contains(name, "·")) + bwritef(output, "%s·", package); + bwritef(output, "%s(", name); - bwritef(output, "void\n%s·%s(", package, name); first = 1; write_params(params, &first); @@ -518,6 +547,24 @@ write_6g_func_header(char *package, char *name, struct params *params, write_params(rets, &first); bwritef(output, ")\n{\n"); + + for (p = rets; p != nil; p = p->next) { + if(streq(p->name, "...")) + continue; + if(streq(p->type, "Slice")) + bwritef(output, "\t%s.array = 0;\n\t%s.len = 0;\n\t%s.cap = 0;\n", p->name, p->name, p->name); + else if(streq(p->type, "String")) + bwritef(output, "\t%s.str = 0;\n\t%s.len = 0;\n", p->name, p->name); + else if(streq(p->type, "Eface")) + bwritef(output, "\t%s.type = 0;\n\t%s.data = 0;\n", p->name, p->name); + else if(streq(p->type, "Iface")) + bwritef(output, "\t%s.tab = 0;\n\t%s.data = 0;\n", p->name, p->name); + else if(streq(p->type, "Complex128")) + bwritef(output, "\t%s.real = 0;\n\t%s.imag = 0;\n", p->name, p->name); + else + bwritef(output, "\t%s = 0;\n", p->name); + bwritef(output, "\tFLUSH(&%s);\n", p->name); + } } /* Write a 6g function trailer. */ @@ -527,7 +574,8 @@ write_6g_func_trailer(struct params *rets) struct params *p; for (p = rets; p != nil; p = p->next) - bwritef(output, "\tFLUSH(&%s);\n", p->name); + if(!streq(p->name, "...")) + bwritef(output, "\tFLUSH(&%s);\n", p->name); bwritef(output, "}\n"); } @@ -726,6 +774,7 @@ process_file(void) void goc2c(char *goc, char *c) { + int i; Buf in, out; binit(&in); @@ -739,13 +788,15 @@ goc2c(char *goc, char *c) if(!gcc) { if(streq(goarch, "amd64")) { type_table[Uintptr].size = 8; - type_table[Eface].size = 8+8; - type_table[String].size = 16; if(use64bitint) { type_table[Int].size = 8; - type_table[Uint].size = 8; + } else { + type_table[Int].size = 4; } - type_table[Slice].size = 8+2*type_table[Int].size; + structround = 8; + } else if(streq(goarch, "amd64p32")) { + type_table[Uintptr].size = 4; + type_table[Int].size = 4; structround = 8; } else { // NOTE: These are set in the initializer, @@ -753,13 +804,22 @@ goc2c(char *goc, char *c) // previous invocation of goc2c, so we have // to restore them. type_table[Uintptr].size = 4; - type_table[String].size = 8; - type_table[Slice].size = 16; - type_table[Eface].size = 4+4; type_table[Int].size = 4; - type_table[Uint].size = 4; structround = 4; } + + type_table[Uint].size = type_table[Int].size; + type_table[Slice].size = type_table[Uintptr].size+2*type_table[Int].size; + type_table[Eface].size = 2*type_table[Uintptr].size; + type_table[String].size = 2*type_table[Uintptr].size; + + for(i=0; i #include #include +#include // bprintf replaces the buffer with the result of the printf formatting // and returns a pointer to the NUL-terminated buffer contents. @@ -686,6 +687,14 @@ main(int argc, char **argv) gohostos = "openbsd"; #elif defined(__NetBSD__) gohostos = "netbsd"; +#elif defined(__sun) && defined(__SVR4) + gohostos = "solaris"; + // Even on 64-bit platform, solaris uname -m prints i86pc. + run(&b, nil, 0, "isainfo", "-n", nil); + if(contains(bstr(&b), "amd64")) + gohostarch = "amd64"; + if(contains(bstr(&b), "i386")) + gohostarch = "386"; #else fatal("unknown operating system"); #endif diff --git a/src/cmd/dist/windows.c b/src/cmd/dist/windows.c index 7d03989b2..2839c4bc5 100644 --- a/src/cmd/dist/windows.c +++ b/src/cmd/dist/windows.c @@ -840,34 +840,20 @@ void xprintf(char *fmt, ...) { va_list arg; - char *p; - DWORD n, w; - + va_start(arg, fmt); - n = vsnprintf(NULL, 0, fmt, arg); - p = xmalloc(n+1); - vsnprintf(p, n+1, fmt, arg); + vprintf(fmt, arg); va_end(arg); - w = 0; - WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), p, n, &w, 0); - xfree(p); } void errprintf(char *fmt, ...) { va_list arg; - char *p; - DWORD n, w; - + va_start(arg, fmt); - n = vsnprintf(NULL, 0, fmt, arg); - p = xmalloc(n+1); - vsnprintf(p, n+1, fmt, arg); + vfprintf(stderr, fmt, arg); va_end(arg); - w = 0; - WriteFile(GetStdHandle(STD_ERROR_HANDLE), p, n, &w, 0); - xfree(p); } int diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c index 8e9677e75..b809640e4 100644 --- a/src/cmd/gc/align.c +++ b/src/cmd/gc/align.c @@ -175,11 +175,11 @@ dowidth(Type *t) case TFLOAT64: case TCOMPLEX64: w = 8; - t->align = widthptr; + t->align = widthreg; break; case TCOMPLEX128: w = 16; - t->align = widthptr; + t->align = widthreg; break; case TPTR32: w = 4; @@ -288,10 +288,10 @@ dowidth(Type *t) // compute their widths as side-effect. t1 = t->type; w = widstruct(t->type, *getthis(t1), 0, 0); - w = widstruct(t->type, *getinarg(t1), w, widthptr); - w = widstruct(t->type, *getoutarg(t1), w, widthptr); + w = widstruct(t->type, *getinarg(t1), w, widthreg); + w = widstruct(t->type, *getoutarg(t1), w, widthreg); t1->argwid = w; - if(w%widthptr) + if(w%widthreg) warn("bad type %T %d\n", t1, w); t->align = 1; break; diff --git a/src/cmd/gc/array.c b/src/cmd/gc/array.c new file mode 100644 index 000000000..5e53c1ff0 --- /dev/null +++ b/src/cmd/gc/array.c @@ -0,0 +1,129 @@ +// Copyright 2013 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 +#include +#include "go.h" + +enum { + DEFAULTCAPACITY = 16, +}; + +struct Array +{ + int32 length; // number of elements + int32 size; // element size + int32 capacity; // size of data in elements + char *data; // element storage +}; + +Array* +arraynew(int32 capacity, int32 size) +{ + Array *result; + + if(capacity < 0) + fatal("arraynew: capacity %d is not positive", capacity); + if(size < 0) + fatal("arraynew: size %d is not positive\n", size); + result = malloc(sizeof(*result)); + if(result == nil) + fatal("arraynew: malloc failed\n"); + result->length = 0; + result->size = size; + result->capacity = capacity == 0 ? DEFAULTCAPACITY : capacity; + result->data = malloc(result->capacity * result->size); + if(result->data == nil) + fatal("arraynew: malloc failed\n"); + return result; +} + +void +arrayfree(Array *array) +{ + if(array == nil) + return; + free(array->data); + free(array); +} + +int32 +arraylength(Array *array) +{ + return array->length; +} + +void* +arrayget(Array *array, int32 index) +{ + if(array == nil) + fatal("arrayget: array is nil\n"); + if(index < 0 || index >= array->length) + fatal("arrayget: index %d is out of bounds for length %d\n", index, array->length); + return array->data + index * array->size; +} + +void +arrayset(Array *array, int32 index, void *element) +{ + if(array == nil) + fatal("arrayset: array is nil\n"); + if(element == nil) + fatal("arrayset: element is nil\n"); + if(index < 0 || index >= array->length) + fatal("arrayget: index %d is out of bounds for length %d\n", index, array->length); + memmove(array->data + index * array->size, element, array->size); +} + +static void +ensurecapacity(Array *array, int32 capacity) +{ + int32 newcapacity; + char *newdata; + + if(array == nil) + fatal("ensurecapacity: array is nil\n"); + if(capacity < 0) + fatal("ensurecapacity: capacity %d is not positive", capacity); + if(capacity >= array->capacity) { + newcapacity = capacity + (capacity >> 1); + newdata = realloc(array->data, newcapacity * array->size); + if(newdata == nil) + fatal("ensurecapacity: realloc failed\n"); + array->capacity = newcapacity; + array->data = newdata; + } +} + +void +arrayadd(Array *array, void *element) +{ + if(array == nil) + fatal("arrayset: array is nil\n"); + if(element == nil) + fatal("arrayset: element is nil\n"); + ensurecapacity(array, array->length + 1); + array->length++; + arrayset(array, array->length - 1, element); +} + +int32 +arrayindexof(Array *array, void *element) +{ + void *p; + int32 i; + + for(i = 0; i < array->length; i++) { + p = arrayget(array, i); + if(memcmp(p, &element, array->size) == 0) + return i; + } + return -1; +} + +void +arraysort(Array *array, int (*cmp)(const void*, const void*)) +{ + qsort(array->data, array->length, array->size, cmp); +} diff --git a/src/cmd/gc/bits.c b/src/cmd/gc/bits.c index c0fd4d85e..2e79f6f1d 100644 --- a/src/cmd/gc/bits.c +++ b/src/cmd/gc/bits.c @@ -153,7 +153,7 @@ Qconv(Fmt *fp) if(var[i].node == N || var[i].node->sym == S) fmtprint(fp, "$%d", i); else { - fmtprint(fp, "%s", var[i].node->sym->name); + fmtprint(fp, "%s(%d)", var[i].node->sym->name, i); if(var[i].offset != 0) fmtprint(fp, "%+lld", (vlong)var[i].offset); } diff --git a/src/cmd/gc/builtin.c b/src/cmd/gc/builtin.c index 309dc1ea0..5ca5aeb77 100644 --- a/src/cmd/gc/builtin.c +++ b/src/cmd/gc/builtin.c @@ -5,6 +5,7 @@ char *runtimeimport = "func @\"\".new (@\"\".typ·2 *byte) (? *any)\n" "func @\"\".panicindex ()\n" "func @\"\".panicslice ()\n" + "func @\"\".panicdivide ()\n" "func @\"\".throwreturn ()\n" "func @\"\".throwinit ()\n" "func @\"\".panicwrap (? string, ? string, ? string)\n" @@ -23,11 +24,16 @@ char *runtimeimport = "func @\"\".printnl ()\n" "func @\"\".printsp ()\n" "func @\"\".goprintf ()\n" - "func @\"\".concatstring ()\n" + "func @\"\".concatstring2 (? string, ? string) (? string)\n" + "func @\"\".concatstring3 (? string, ? string, ? string) (? string)\n" + "func @\"\".concatstring4 (? string, ? string, ? string, ? string) (? string)\n" + "func @\"\".concatstring5 (? string, ? string, ? string, ? string, ? string) (? string)\n" + "func @\"\".concatstrings (? []string) (? string)\n" "func @\"\".cmpstring (? string, ? string) (? int)\n" "func @\"\".eqstring (? string, ? string) (? bool)\n" "func @\"\".intstring (? int64) (? string)\n" "func @\"\".slicebytetostring (? []byte) (? string)\n" + "func @\"\".slicebytetostringtmp (? []byte) (? string)\n" "func @\"\".slicerunetostring (? []rune) (? string)\n" "func @\"\".stringtoslicebyte (? string) (? []byte)\n" "func @\"\".stringtoslicerune (? string) (? []rune)\n" @@ -38,8 +44,8 @@ char *runtimeimport = "func @\"\".typ2Itab (@\"\".typ·2 *byte, @\"\".typ2·3 *byte, @\"\".cache·4 **byte) (@\"\".ret·1 *byte)\n" "func @\"\".convI2E (@\"\".elem·2 any) (@\"\".ret·1 any)\n" "func @\"\".convI2I (@\"\".typ·2 *byte, @\"\".elem·3 any) (@\"\".ret·1 any)\n" - "func @\"\".convT2E (@\"\".typ·2 *byte, @\"\".elem·3 any) (@\"\".ret·1 any)\n" - "func @\"\".convT2I (@\"\".typ·2 *byte, @\"\".typ2·3 *byte, @\"\".cache·4 **byte, @\"\".elem·5 any) (@\"\".ret·1 any)\n" + "func @\"\".convT2E (@\"\".typ·2 *byte, @\"\".elem·3 *any) (@\"\".ret·1 any)\n" + "func @\"\".convT2I (@\"\".typ·2 *byte, @\"\".typ2·3 *byte, @\"\".cache·4 **byte, @\"\".elem·5 *any) (@\"\".ret·1 any)\n" "func @\"\".assertE2E (@\"\".typ·2 *byte, @\"\".iface·3 any) (@\"\".ret·1 any)\n" "func @\"\".assertE2E2 (@\"\".typ·3 *byte, @\"\".iface·4 any) (@\"\".ret·1 any, @\"\".ok·2 bool)\n" "func @\"\".assertE2I (@\"\".typ·2 *byte, @\"\".iface·3 any) (@\"\".ret·1 any)\n" @@ -60,26 +66,24 @@ char *runtimeimport = "func @\"\".efacethash (@\"\".i1·2 any) (@\"\".ret·1 uint32)\n" "func @\"\".equal (@\"\".typ·2 *byte, @\"\".x1·3 any, @\"\".x2·4 any) (@\"\".ret·1 bool)\n" "func @\"\".makemap (@\"\".mapType·2 *byte, @\"\".hint·3 int64) (@\"\".hmap·1 map[any]any)\n" - "func @\"\".mapaccess1 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 any)\n" + "func @\"\".mapaccess1 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 *any) (@\"\".val·1 *any)\n" "func @\"\".mapaccess1_fast32 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n" "func @\"\".mapaccess1_fast64 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n" "func @\"\".mapaccess1_faststr (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n" - "func @\"\".mapaccess2 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 any, @\"\".pres·2 bool)\n" + "func @\"\".mapaccess2 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 *any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n" "func @\"\".mapaccess2_fast32 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n" "func @\"\".mapaccess2_fast64 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n" "func @\"\".mapaccess2_faststr (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n" - "func @\"\".mapassign1 (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".key·3 any, @\"\".val·4 any)\n" + "func @\"\".mapassign1 (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".key·3 *any, @\"\".val·4 *any)\n" "func @\"\".mapiterinit (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".hiter·3 *any)\n" - "func @\"\".mapdelete (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".key·3 any)\n" + "func @\"\".mapdelete (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".key·3 *any)\n" "func @\"\".mapiternext (@\"\".hiter·1 *any)\n" - "func @\"\".mapiter1 (@\"\".hiter·2 *any) (@\"\".key·1 any)\n" - "func @\"\".mapiter2 (@\"\".hiter·3 *any) (@\"\".key·1 any, @\"\".val·2 any)\n" "func @\"\".makechan (@\"\".chanType·2 *byte, @\"\".hint·3 int64) (@\"\".hchan·1 chan any)\n" - "func @\"\".chanrecv1 (@\"\".chanType·2 *byte, @\"\".hchan·3 <-chan any) (@\"\".elem·1 any)\n" - "func @\"\".chanrecv2 (@\"\".chanType·3 *byte, @\"\".hchan·4 <-chan any) (@\"\".elem·1 any, @\"\".received·2 bool)\n" - "func @\"\".chansend1 (@\"\".chanType·1 *byte, @\"\".hchan·2 chan<- any, @\"\".elem·3 any)\n" + "func @\"\".chanrecv1 (@\"\".chanType·1 *byte, @\"\".hchan·2 <-chan any, @\"\".elem·3 *any)\n" + "func @\"\".chanrecv2 (@\"\".chanType·2 *byte, @\"\".hchan·3 <-chan any, @\"\".elem·4 *any) (? bool)\n" + "func @\"\".chansend1 (@\"\".chanType·1 *byte, @\"\".hchan·2 chan<- any, @\"\".elem·3 *any)\n" "func @\"\".closechan (@\"\".hchan·1 any)\n" - "func @\"\".selectnbsend (@\"\".chanType·2 *byte, @\"\".hchan·3 chan<- any, @\"\".elem·4 any) (? bool)\n" + "func @\"\".selectnbsend (@\"\".chanType·2 *byte, @\"\".hchan·3 chan<- any, @\"\".elem·4 *any) (? bool)\n" "func @\"\".selectnbrecv (@\"\".chanType·2 *byte, @\"\".elem·3 *any, @\"\".hchan·4 <-chan any) (? bool)\n" "func @\"\".selectnbrecv2 (@\"\".chanType·2 *byte, @\"\".elem·3 *any, @\"\".received·4 *bool, @\"\".hchan·5 <-chan any) (? bool)\n" "func @\"\".newselect (@\"\".size·2 int32) (@\"\".sel·1 *byte)\n" diff --git a/src/cmd/gc/bv.c b/src/cmd/gc/bv.c index 92834a97b..2efbbc565 100644 --- a/src/cmd/gc/bv.c +++ b/src/cmd/gc/bv.c @@ -11,12 +11,24 @@ enum { WORDBITS = 32, }; -uintptr +static uintptr bvsize(uintptr n) { return ((n + WORDBITS - 1) / WORDBITS) * WORDSIZE; } +int32 +bvbits(Bvec *bv) +{ + return bv->n; +} + +int32 +bvwords(Bvec *bv) +{ + return (bv->n + WORDBITS - 1) / WORDBITS; +} + Bvec* bvalloc(int32 n) { @@ -34,26 +46,49 @@ bvalloc(int32 n) return bv; } +/* difference */ void -bvset(Bvec *bv, int32 i) +bvandnot(Bvec *dst, Bvec *src1, Bvec *src2) { - uint32 mask; + int32 i, w; - if(i < 0 || i >= bv->n) - fatal("bvset: index %d is out of bounds with length %d\n", i, bv->n); - mask = 1U << (i % WORDBITS); - bv->b[i / WORDBITS] |= mask; + if(dst->n != src1->n || dst->n != src2->n) + fatal("bvand: lengths %d, %d, and %d are not equal", dst->n, src1->n, src2->n); + for(i = 0, w = 0; i < dst->n; i += WORDBITS, w++) + dst->b[w] = src1->b[w] & ~src2->b[w]; +} + +int +bvcmp(Bvec *bv1, Bvec *bv2) +{ + uintptr nbytes; + + if(bv1->n != bv2->n) + fatal("bvequal: lengths %d and %d are not equal", bv1->n, bv2->n); + nbytes = bvsize(bv1->n); + return memcmp(bv1->b, bv2->b, nbytes); } void -bvres(Bvec *bv, int32 i) +bvcopy(Bvec *dst, Bvec *src) { - uint32 mask; + memmove(dst->b, src->b, bvsize(dst->n)); +} - if(i < 0 || i >= bv->n) - fatal("bvres: index %d is out of bounds with length %d\n", i, bv->n); - mask = ~(1 << (i % WORDBITS)); - bv->b[i / WORDBITS] &= mask; +Bvec* +bvconcat(Bvec *src1, Bvec *src2) +{ + Bvec *dst; + int32 i; + + dst = bvalloc(src1->n + src2->n); + for(i = 0; i < src1->n; i++) + if(bvget(src1, i)) + bvset(dst, i); + for(i = 0; i < src2->n; i++) + if(bvget(src2, i)) + bvset(dst, i + src1->n); + return dst; } int @@ -63,7 +98,7 @@ bvget(Bvec *bv, int32 i) if(i < 0 || i >= bv->n) fatal("bvget: index %d is out of bounds with length %d\n", i, bv->n); - mask = 1 << (i % WORDBITS); + mask = 1U << (i % WORDBITS); word = bv->b[i / WORDBITS] & mask; return word ? 1 : 0; } @@ -78,3 +113,74 @@ bvisempty(Bvec *bv) return 0; return 1; } + +void +bvnot(Bvec *bv) +{ + int32 i, w; + + for(i = 0, w = 0; i < bv->n; i += WORDBITS, w++) + bv->b[w] = ~bv->b[w]; +} + +/* union */ +void +bvor(Bvec *dst, Bvec *src1, Bvec *src2) +{ + int32 i, w; + + if(dst->n != src1->n || dst->n != src2->n) + fatal("bvor: lengths %d, %d, and %d are not equal", dst->n, src1->n, src2->n); + for(i = 0, w = 0; i < dst->n; i += WORDBITS, w++) + dst->b[w] = src1->b[w] | src2->b[w]; +} + +/* intersection */ +void +bvand(Bvec *dst, Bvec *src1, Bvec *src2) +{ + int32 i, w; + + if(dst->n != src1->n || dst->n != src2->n) + fatal("bvor: lengths %d, %d, and %d are not equal", dst->n, src1->n, src2->n); + for(i = 0, w = 0; i < dst->n; i += WORDBITS, w++) + dst->b[w] = src1->b[w] & src2->b[w]; +} + +void +bvprint(Bvec *bv) +{ + int32 i; + + print("#*"); + for(i = 0; i < bv->n; i++) + print("%d", bvget(bv, i)); +} + +void +bvreset(Bvec *bv, int32 i) +{ + uint32 mask; + + if(i < 0 || i >= bv->n) + fatal("bvreset: index %d is out of bounds with length %d\n", i, bv->n); + mask = ~(1 << (i % WORDBITS)); + bv->b[i / WORDBITS] &= mask; +} + +void +bvresetall(Bvec *bv) +{ + memset(bv->b, 0x00, bvsize(bv->n)); +} + +void +bvset(Bvec *bv, int32 i) +{ + uint32 mask; + + if(i < 0 || i >= bv->n) + fatal("bvset: index %d is out of bounds with length %d\n", i, bv->n); + mask = 1U << (i % WORDBITS); + bv->b[i / WORDBITS] |= mask; +} diff --git a/src/cmd/gc/closure.c b/src/cmd/gc/closure.c index 5a84dfb1b..ad4e5bd02 100644 --- a/src/cmd/gc/closure.c +++ b/src/cmd/gc/closure.c @@ -161,6 +161,7 @@ makeclosure(Node *func) // and initialize in entry prologue. body = nil; offset = widthptr; + xfunc->needctxt = func->cvars != nil; for(l=func->cvars; l; l=l->next) { v = l->n; if(v->op == 0) @@ -252,6 +253,14 @@ walkclosure(Node *func, NodeList **init) // typecheck will insert a PTRLIT node under CONVNOP, // tag it with escape analysis result. clos->left->esc = func->esc; + // non-escaping temp to use, if any. + // orderexpr did not compute the type; fill it in now. + if(func->alloc != N) { + func->alloc->type = clos->left->left->type; + func->alloc->orig->type = func->alloc->type; + clos->left->right = func->alloc; + func->alloc = N; + } walkexpr(&clos, init); return clos; @@ -361,9 +370,12 @@ makepartialcall(Node *fn, Type *t0, Node *meth) // Declare and initialize variable holding receiver. body = nil; + xfunc->needctxt = 1; cv = nod(OCLOSUREVAR, N, N); cv->xoffset = widthptr; cv->type = rcvrtype; + if(cv->type->align > widthptr) + cv->xoffset = cv->type->align; ptr = nod(ONAME, N, N); ptr->sym = lookup("rcvr"); ptr->class = PAUTO; @@ -441,6 +453,14 @@ walkpartialcall(Node *n, NodeList **init) // typecheck will insert a PTRLIT node under CONVNOP, // tag it with escape analysis result. clos->left->esc = n->esc; + // non-escaping temp to use, if any. + // orderexpr did not compute the type; fill it in now. + if(n->alloc != N) { + n->alloc->type = clos->left->left->type; + n->alloc->orig->type = n->alloc->type; + clos->left->right = n->alloc; + n->alloc = N; + } walkexpr(&clos, init); return clos; diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c index cfb1f0ade..143c1730d 100644 --- a/src/cmd/gc/const.c +++ b/src/cmd/gc/const.c @@ -22,19 +22,22 @@ Mpflt* truncfltlit(Mpflt *oldv, Type *t) { double d; - float f; Mpflt *fv; + Val v; if(t == T) return oldv; + memset(&v, 0, sizeof v); + v.ctype = CTFLT; + v.u.fval = oldv; + overflow(v, t); + fv = mal(sizeof *fv); *fv = *oldv; // convert large precision literal floating // into limited precision (float64 or float32) - // botch -- this assumes that compiler fp - // has same precision as runtime fp switch(t->etype) { case TFLOAT64: d = mpgetflt(fv); @@ -42,10 +45,9 @@ truncfltlit(Mpflt *oldv, Type *t) break; case TFLOAT32: - d = mpgetflt(fv); - f = d; - d = f; + d = mpgetflt32(fv); mpmovecflt(fv, d); + break; } return fv; @@ -235,7 +237,6 @@ convlit1(Node **np, Type *t, int explicit) n->val = toflt(n->val); // flowthrough case CTFLT: - overflow(n->val, t); n->val.u.fval = truncfltlit(n->val.u.fval, t); break; } @@ -521,6 +522,7 @@ evconst(Node *n) int wl, wr, lno, et; Val v, rv; Mpint b; + NodeList *l1, *l2; // pick off just the opcodes that can be // constant evaluated. @@ -528,7 +530,6 @@ evconst(Node *n) default: return; case OADD: - case OADDSTR: case OAND: case OANDAND: case OANDNOT: @@ -559,6 +560,47 @@ evconst(Node *n) if(!okforconst[n->type->etype] && n->type->etype != TNIL) return; break; + + case OADDSTR: + // merge adjacent constants in the argument list. + for(l1=n->list; l1 != nil; l1= l1->next) { + if(isconst(l1->n, CTSTR) && l1->next != nil && isconst(l1->next->n, CTSTR)) { + l2 = l1; + len = 0; + while(l2 != nil && isconst(l2->n, CTSTR)) { + nr = l2->n; + len += nr->val.u.sval->len; + l2 = l2->next; + } + // merge from l1 up to but not including l2 + str = mal(sizeof(*str) + len); + str->len = len; + len = 0; + l2 = l1; + while(l2 != nil && isconst(l2->n, CTSTR)) { + nr = l2->n; + memmove(str->s+len, nr->val.u.sval->s, nr->val.u.sval->len); + len += nr->val.u.sval->len; + l2 = l2->next; + } + nl = nod(OXXX, N, N); + *nl = *l1->n; + nl->orig = nl; + nl->val.ctype = CTSTR; + nl->val.u.sval = str; + l1->n = nl; + l1->next = l2; + } + } + // fix list end pointer. + for(l2=n->list; l2 != nil; l2=l2->next) + n->list->end = l2; + // collapse single-constant list to single constant. + if(count(n->list) == 1 && isconst(n->list->n, CTSTR)) { + n->op = OLITERAL; + n->val = n->list->n->val; + } + return; } nl = n->left; @@ -861,15 +903,6 @@ evconst(Node *n) if(cmpslit(nl, nr) > 0) goto settrue; goto setfalse; - case TUP(OADDSTR, CTSTR): - len = v.u.sval->len + rv.u.sval->len; - str = mal(sizeof(*str) + len); - str->len = len; - memcpy(str->s, v.u.sval->s, v.u.sval->len); - memcpy(str->s+v.u.sval->len, rv.u.sval->s, rv.u.sval->len); - str->len = len; - v.u.sval = str; - break; case TUP(OOROR, CTBOOL): if(v.u.bval || rv.u.bval) @@ -918,6 +951,7 @@ unary: case TUP(OCONV, CTFLT): case TUP(OCONV, CTSTR): convlit1(&nl, n->type, 1); + v = nl->val; break; case TUP(OPLUS, CTINT): @@ -1144,7 +1178,10 @@ defaultlit(Node **np, Type *t) } if(n->val.ctype == CTNIL) { lineno = lno; - yyerror("use of untyped nil"); + if(!n->diag) { + yyerror("use of untyped nil"); + n->diag = 1; + } n->type = T; break; } @@ -1559,7 +1596,7 @@ isgoconst(Node *n) case ONAME: l = n->sym->def; - if(l->op == OLITERAL && n->val.ctype != CTNIL) + if(l && l->op == OLITERAL && n->val.ctype != CTNIL) return 1; break; @@ -1594,10 +1631,25 @@ hascallchan(Node *n) if(n == N) return 0; switch(n->op) { + case OAPPEND: case OCALL: case OCALLFUNC: - case OCALLMETH: case OCALLINTER: + case OCALLMETH: + case OCAP: + case OCLOSE: + case OCOMPLEX: + case OCOPY: + case ODELETE: + case OIMAG: + case OLEN: + case OMAKE: + case ONEW: + case OPANIC: + case OPRINT: + case OPRINTN: + case OREAL: + case ORECOVER: case ORECV: return 1; } diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c index c7d13ef06..73c2581be 100644 --- a/src/cmd/gc/dcl.c +++ b/src/cmd/gc/dcl.c @@ -130,7 +130,7 @@ dumpdcl(char *st) } print(" '%s'", d->name); s = pkglookup(d->name, d->pkg); - print(" %lS\n", s); + print(" %S\n", s); } } @@ -643,8 +643,8 @@ funcargs(Node *nt) fatal("funcargs out %O", n->op); if(n->left == N) { - // give it a name so escape analysis has nodes to work with - snprint(namebuf, sizeof(namebuf), "~anon%d", gen++); + // Name so that escape analysis can track it. ~r stands for 'result'. + snprint(namebuf, sizeof(namebuf), "~r%d", gen++); n->left = newname(lookup(namebuf)); // TODO: n->left->missing = 1; } @@ -652,14 +652,20 @@ funcargs(Node *nt) n->left->op = ONAME; if(isblank(n->left)) { - // Give it a name so we can assign to it during return. - // preserve the original in ->orig + // Give it a name so we can assign to it during return. ~b stands for 'blank'. + // The name must be different from ~r above because if you have + // func f() (_ int) + // func g() int + // f is allowed to use a plain 'return' with no arguments, while g is not. + // So the two cases must be distinguished. + // We do not record a pointer to the original node (n->orig). + // Having multiple names causes too much confusion in later passes. nn = nod(OXXX, N, N); *nn = *n->left; + nn->orig = nn; + snprint(namebuf, sizeof(namebuf), "~b%d", gen++); + nn->sym = lookup(namebuf); n->left = nn; - - snprint(namebuf, sizeof(namebuf), "~anon%d", gen++); - n->left->sym = lookup(namebuf); } n->left->ntype = n->right; @@ -941,8 +947,6 @@ interfacefield(Node *n) f->nname = n->left; f->embedded = n->embedded; f->sym = f->nname->sym; - if(importpkg && !exportname(f->sym->name)) - f->sym = pkglookup(f->sym->name, structpkg); } } else { @@ -1211,7 +1215,7 @@ functype(Node *this, NodeList *in, NodeList *out) t->outnamed = 0; if(t->outtuple > 0 && out->n->left != N && out->n->left->orig != N) { s = out->n->left->orig->sym; - if(s != S && s->name[0] != '~') + if(s != S && (s->name[0] != '~' || s->name[1] != 'r')) // ~r%d is the name invented for an unnamed result t->outnamed = 1; } @@ -1434,6 +1438,8 @@ funccompile(Node *n, int isclosure) // record offset to actual frame pointer. // for closure, have to skip over leading pointers and PC slot. + // TODO(rsc): this is the old jit closure handling code. + // with the new closures, isclosure is always 0; delete this block. nodfp->xoffset = 0; if(isclosure) { NodeList *l; diff --git a/src/cmd/gc/doc.go b/src/cmd/gc/doc.go index 791967708..03df93a3e 100644 --- a/src/cmd/gc/doc.go +++ b/src/cmd/gc/doc.go @@ -37,6 +37,8 @@ Substitute 6g with 8g or 5g where appropriate. Flags: -o file output file, default file.6 for 6g, etc. + -pack + write an archive file rather than an object file -e normally the compiler quits after 10 errors; -e prints all errors -p path @@ -50,12 +52,14 @@ Flags: add dir1 and dir2 to the list of paths to check for imported packages -N disable optimizations + -nolocalimports + disallow local (relative) imports -S write assembly language text to standard output (code only) -S -S write assembly language text to standard output (code and data) -u - disallow importing packages not marked as safe + disallow importing packages not marked as safe; implies -nolocalimports -V print the compiler version -race diff --git a/src/cmd/gc/esc.c b/src/cmd/gc/esc.c index b84b66ef1..78624d7cb 100644 --- a/src/cmd/gc/esc.c +++ b/src/cmd/gc/esc.c @@ -185,12 +185,12 @@ visitcode(Node *n, uint32 min) typedef struct EscState EscState; static void escfunc(EscState*, Node *func); -static void esclist(EscState*, NodeList *l); -static void esc(EscState*, Node *n); +static void esclist(EscState*, NodeList *l, Node *up); +static void esc(EscState*, Node *n, Node *up); static void escloopdepthlist(EscState*, NodeList *l); static void escloopdepth(EscState*, Node *n); static void escassign(EscState*, Node *dst, Node *src); -static void esccall(EscState*, Node*); +static void esccall(EscState*, Node*, Node *up); static void escflows(EscState*, Node *dst, Node *src); static void escflood(EscState*, Node *dst); static void escwalk(EscState*, int level, Node *dst, Node *src); @@ -204,6 +204,13 @@ struct EscState { // flow to. Node theSink; + // If an analyzed function is recorded to return + // pieces obtained via indirection from a parameter, + // and later there is a call f(x) to that function, + // we create a link funcParam <- x to record that fact. + // The funcParam node is handled specially in escflood. + Node funcParam; + NodeList* dsts; // all dst nodes int loopdepth; // for detecting nested loop scopes int pdepth; // for debug printing in recursions. @@ -269,7 +276,13 @@ analyze(NodeList *all, int recursive) e->theSink.sym = lookup(".sink"); e->theSink.escloopdepth = -1; e->recursive = recursive; - + + e->funcParam.op = ONAME; + e->funcParam.orig = &e->funcParam; + e->funcParam.class = PAUTO; + e->funcParam.sym = lookup(".param"); + e->funcParam.escloopdepth = 10000000; + for(l=all; l; l=l->next) if(l->n->op == ODCLFUNC) l->n->esc = EscFuncPlanned; @@ -328,6 +341,7 @@ escfunc(EscState *e, Node *func) ll->n->escloopdepth = 0; break; case PPARAM: + ll->n->escloopdepth = 1; if(ll->n->type && !haspointers(ll->n->type)) break; if(curfn->nbody == nil && !curfn->noescape) @@ -335,7 +349,6 @@ escfunc(EscState *e, Node *func) else ll->n->esc = EscNone; // prime for escflood later e->noesc = list(e->noesc, ll->n); - ll->n->escloopdepth = 1; break; } } @@ -347,7 +360,7 @@ escfunc(EscState *e, Node *func) escflows(e, &e->theSink, ll->n); escloopdepthlist(e, curfn->nbody); - esclist(e, curfn->nbody); + esclist(e, curfn->nbody, curfn); curfn = savefn; e->loopdepth = saveld; } @@ -405,14 +418,14 @@ escloopdepth(EscState *e, Node *n) } static void -esclist(EscState *e, NodeList *l) +esclist(EscState *e, NodeList *l, Node *up) { for(; l; l=l->next) - esc(e, l->n); + esc(e, l->n, up); } static void -esc(EscState *e, Node *n) +esc(EscState *e, Node *n, Node *up) { int lno; NodeList *ll, *lr; @@ -423,18 +436,32 @@ esc(EscState *e, Node *n) lno = setlineno(n); + // ninit logically runs at a different loopdepth than the rest of the for loop. + esclist(e, n->ninit, n); + if(n->op == OFOR || n->op == ORANGE) e->loopdepth++; - esc(e, n->left); - esc(e, n->right); - esc(e, n->ntest); - esc(e, n->nincr); - esclist(e, n->ninit); - esclist(e, n->nbody); - esclist(e, n->nelse); - esclist(e, n->list); - esclist(e, n->rlist); + // type switch variables have no ODCL. + // process type switch as declaration. + // must happen before processing of switch body, + // so before recursion. + if(n->op == OSWITCH && n->ntest && n->ntest->op == OTYPESW) { + for(ll=n->list; ll; ll=ll->next) { // cases + // ll->n->nname is the variable per case + if(ll->n->nname) + ll->n->nname->escloopdepth = e->loopdepth; + } + } + + esc(e, n->left, n); + esc(e, n->right, n); + esc(e, n->ntest, n); + esc(e, n->nincr, n); + esclist(e, n->nbody, n); + esclist(e, n->nelse, n); + esclist(e, n->list, n); + esclist(e, n->rlist, n); if(n->op == OFOR || n->op == ORANGE) e->loopdepth--; @@ -520,7 +547,7 @@ esc(EscState *e, Node *n) case OCALLMETH: case OCALLFUNC: case OCALLINTER: - esccall(e, n); + esccall(e, n, up); break; case OAS2FUNC: // x,y = f() @@ -628,7 +655,6 @@ esc(EscState *e, Node *n) escassign(e, n, a); } // fallthrough - case OADDR: case OMAKECHAN: case OMAKEMAP: case OMAKESLICE: @@ -637,6 +663,35 @@ esc(EscState *e, Node *n) n->esc = EscNone; // until proven otherwise e->noesc = list(e->noesc, n); break; + + case OADDR: + n->esc = EscNone; // until proven otherwise + e->noesc = list(e->noesc, n); + // current loop depth is an upper bound on actual loop depth + // of addressed value. + n->escloopdepth = e->loopdepth; + // for &x, use loop depth of x if known. + // it should always be known, but if not, be conservative + // and keep the current loop depth. + if(n->left->op == ONAME) { + switch(n->left->class) { + case PAUTO: + if(n->left->escloopdepth != 0) + n->escloopdepth = n->left->escloopdepth; + break; + case PPARAM: + case PPARAMOUT: + // PPARAM is loop depth 1 always. + // PPARAMOUT is loop depth 0 for writes + // but considered loop depth 1 for address-of, + // so that writing the address of one result + // to another (or the same) result makes the + // first result move to the heap. + n->escloopdepth = 1; + break; + } + } + break; } lineno = lno; @@ -748,8 +803,8 @@ escassign(EscState *e, Node *dst, Node *src) case ODOTTYPE: case ODOTTYPE2: case OSLICE: - case OSLICEARR: case OSLICE3: + case OSLICEARR: case OSLICE3ARR: // Conversions, field access, slice all preserve the input value. escassign(e, dst, src->left); @@ -792,24 +847,34 @@ escassign(EscState *e, Node *dst, Node *src) lineno = lno; } -static void +static int escassignfromtag(EscState *e, Strlit *note, NodeList *dsts, Node *src) { - int em; + int em, em0; em = parsetag(note); - + if(em == EscUnknown) { escassign(e, &e->theSink, src); - return; + return em; } - - for(em >>= EscBits; em && dsts; em >>= 1, dsts=dsts->next) + + if(em == EscNone) + return em; + + // If content inside parameter (reached via indirection) + // escapes back to results, mark as such. + if(em & EscContentEscapes) + escassign(e, &e->funcParam, src); + + em0 = em; + for(em >>= EscReturnBits; em && dsts; em >>= 1, dsts=dsts->next) if(em & 1) escassign(e, dsts->n, src); if (em != 0 && dsts == nil) fatal("corrupt esc tag %Z or messed up escretval list\n", note); + return em0; } // This is a bit messier than fortunate, pulled out of esc's big @@ -819,7 +884,7 @@ escassignfromtag(EscState *e, Strlit *note, NodeList *dsts, Node *src) // different for methods vs plain functions and for imported vs // this-package static void -esccall(EscState *e, Node *n) +esccall(EscState *e, Node *n, Node *up) { NodeList *ll, *lr; Node *a, *fn, *src; @@ -856,7 +921,7 @@ esccall(EscState *e, Node *n) if(a->type->etype == TSTRUCT && a->type->funarg) // f(g()). ll = a->escretval; } - + if(fn && fn->op == ONAME && fn->class == PFUNC && fn->defn && fn->defn->nbody && fn->ntype && fn->defn->esc < EscFuncTagged) { // function in same mutually recursive group. Incorporate into flow graph. // print("esc local fn: %N\n", fn->ntype); @@ -876,6 +941,10 @@ esccall(EscState *e, Node *n) if(lr->n->isddd && !n->isddd) { // Introduce ODDDARG node to represent ... allocation. src = nod(ODDDARG, N, N); + src->type = typ(TARRAY); + src->type->type = lr->n->type->type; + src->type->bound = count(ll); + src->type = ptrto(src->type); // make pointer so it will be tracked src->escloopdepth = e->loopdepth; src->lineno = n->lineno; src->esc = EscNone; // until we find otherwise @@ -916,8 +985,12 @@ esccall(EscState *e, Node *n) // print("esc analyzed fn: %#N (%+T) returning (%+H)\n", fn, fntype, n->escretval); // Receiver. - if(n->op != OCALLFUNC) - escassignfromtag(e, getthisx(fntype)->type->note, n->escretval, n->left->left); + if(n->op != OCALLFUNC) { + t = getthisx(fntype)->type; + src = n->left->left; + if(haspointers(t->type)) + escassignfromtag(e, t->note, n->escretval, src); + } for(t=getinargx(fntype)->type; ll; ll=ll->next) { src = ll->n; @@ -926,11 +999,40 @@ esccall(EscState *e, Node *n) src = nod(ODDDARG, N, N); src->escloopdepth = e->loopdepth; src->lineno = n->lineno; + src->type = typ(TARRAY); + src->type->type = t->type->type; + src->type->bound = count(ll); + src->type = ptrto(src->type); // make pointer so it will be tracked src->esc = EscNone; // until we find otherwise e->noesc = list(e->noesc, src); n->right = src; } - escassignfromtag(e, t->note, n->escretval, src); + if(haspointers(t->type)) { + if(escassignfromtag(e, t->note, n->escretval, src) == EscNone && up->op != ODEFER && up->op != OPROC) { + a = src; + while(a->op == OCONVNOP) + a = a->left; + switch(a->op) { + case OCALLPART: + case OCLOSURE: + case ODDDARG: + case OARRAYLIT: + case OPTRLIT: + case OSTRUCTLIT: + // The callee has already been analyzed, so its arguments have esc tags. + // The argument is marked as not escaping at all. + // Record that fact so that any temporary used for + // synthesizing this expression can be reclaimed when + // the function returns. + // This 'noescape' is even stronger than the usual esc == EscNone. + // src->esc == EscNone means that src does not escape the current function. + // src->noescape = 1 here means that src does not escape this statement + // in the current function. + a->noescape = 1; + break; + } + } + } if(src != ll->n) break; t = t->down; @@ -1029,19 +1131,30 @@ escwalk(EscState *e, int level, Node *dst, Node *src) // Input parameter flowing to output parameter? if(dst->op == ONAME && dst->class == PPARAMOUT && dst->vargen <= 20) { - if(src->op == ONAME && src->class == PPARAM && level == 0 && src->curfn == dst->curfn) { - if(src->esc != EscScope && src->esc != EscHeap) { + if(src->op == ONAME && src->class == PPARAM && src->curfn == dst->curfn && src->esc != EscScope && src->esc != EscHeap) { + if(level == 0) { if(debug['m']) warnl(src->lineno, "leaking param: %hN to result %S", src, dst->sym); if((src->esc&EscMask) != EscReturn) src->esc = EscReturn; - src->esc |= 1<<((dst->vargen-1) + EscBits); + src->esc |= 1<<((dst->vargen-1) + EscReturnBits); + goto recurse; + } else if(level > 0) { + if(debug['m']) + warnl(src->lineno, "%N leaking param %hN content to result %S", src->curfn->nname, src, dst->sym); + if((src->esc&EscMask) != EscReturn) + src->esc = EscReturn; + src->esc |= EscContentEscapes; goto recurse; } } } - leaks = (level <= 0) && (dst->escloopdepth < src->escloopdepth); + // The second clause is for values pointed at by an object passed to a call + // that returns something reached via indirect from the object. + // We don't know which result it is or how many indirects, so we treat it as leaking. + leaks = level <= 0 && dst->escloopdepth < src->escloopdepth || + level < 0 && dst == &e->funcParam && haspointers(src->type); switch(src->op) { case ONAME: @@ -1094,6 +1207,10 @@ escwalk(EscState *e, int level, Node *dst, Node *src) break; case ODOT: + case OSLICE: + case OSLICEARR: + case OSLICE3: + case OSLICE3ARR: escwalk(e, level, dst, src->left); break; @@ -1103,7 +1220,6 @@ escwalk(EscState *e, int level, Node *dst, Node *src) break; } // fall through - case OSLICE: case ODOTPTR: case OINDEXMAP: case OIND: diff --git a/src/cmd/gc/export.c b/src/cmd/gc/export.c index 31bcdf8e7..da5984ceb 100644 --- a/src/cmd/gc/export.c +++ b/src/cmd/gc/export.c @@ -354,7 +354,7 @@ dumpexport(void) lno = lineno; - Bprint(bout, "\n$$ // exports\n package %s", localpkg->name); + Bprint(bout, "\n$$\npackage %s", localpkg->name); if(safemode) Bprint(bout, " safe"); Bprint(bout, "\n"); @@ -369,8 +369,7 @@ dumpexport(void) dumpsym(l->n->sym); } - Bprint(bout, "\n$$ // local types\n\n$$\n"); // 6l expects this. (see ld/go.c) - + Bprint(bout, "\n$$\n"); lineno = lno; } diff --git a/src/cmd/gc/fmt.c b/src/cmd/gc/fmt.c index 9cd344870..b5f8a834f 100644 --- a/src/cmd/gc/fmt.c +++ b/src/cmd/gc/fmt.c @@ -17,7 +17,7 @@ // Flags: "%#O": print go syntax. (automatic unless fmtmode == FDbg) // // %J Node* Node details -// Flags: "%hJ" supresses things not relevant until walk. +// Flags: "%hJ" suppresses things not relevant until walk. // // %V Val* Constant values // @@ -102,75 +102,7 @@ setfmode(unsigned long *flags) static int Lconv(Fmt *fp) { - struct - { - Hist* incl; /* start of this include file */ - int32 idel; /* delta line number to apply to include */ - Hist* line; /* start of this #line directive */ - int32 ldel; /* delta line number to apply to #line */ - } a[HISTSZ]; - int32 lno, d; - int i, n; - Hist *h; - - lno = va_arg(fp->args, int32); - - n = 0; - for(h=hist; h!=H; h=h->link) { - if(h->offset < 0) - continue; - if(lno < h->line) - break; - if(h->name) { - 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++; - } - continue; - } - n--; - if(n > 0 && n < HISTSZ) { - d = h->line - a[n].incl->line; - a[n-1].ldel += d; - a[n-1].idel += d; - } - } - - if(n > HISTSZ) - n = HISTSZ; - - for(i=n-1; i>=0; i--) { - if(i != n-1) { - if(fp->flags & ~(FmtWidth|FmtPrec)) - break; - fmtprint(fp, " "); - } - if(debug['L'] || (fp->flags&FmtLong)) - fmtprint(fp, "%s/", pathname); - if(a[i].line) - 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:%d", - a[i].incl->name, lno-a[i].idel+1); - lno = a[i].incl->line - 1; // now print out start of this file - } - if(n == 0) - fmtprint(fp, ""); - - return 0; + return linklinefmt(ctxt, fp); } static char* @@ -702,9 +634,17 @@ typefmt(Fmt *fp, Type *t) case TSTRUCT: // Format the bucket struct for map[x]y as map.bucket[x]y. // This avoids a recursive print that generates very long names. - if(t->hmap != T) { - t = t->hmap; - return fmtprint(fp, "map.bucket[%T]%T", t->down, t->type); + if(t->map != T) { + if(t->map->bucket == t) { + return fmtprint(fp, "map.bucket[%T]%T", t->map->down, t->map->type); + } + if(t->map->hmap == t) { + return fmtprint(fp, "map.hdr[%T]%T", t->map->down, t->map->type); + } + if(t->map->hiter == t) { + return fmtprint(fp, "map.iter[%T]%T", t->map->down, t->map->type); + } + yyerror("unknown internal map type"); } if(t->funarg) { @@ -738,12 +678,17 @@ typefmt(Fmt *fp, Type *t) if(!(fp->flags&FmtShort)) { s = t->sym; - // Take the name from the original, lest we substituted it with ~anon%d + // Take the name from the original, lest we substituted it with ~r%d or ~b%d. + // ~r%d is a (formerly) unnamed result. if ((fmtmode == FErr || fmtmode == FExp) && t->nname != N) { if(t->nname->orig != N) { s = t->nname->orig->sym; - if(s != S && s->name[0] == '~') - s = S; + if(s != S && s->name[0] == '~') { + if(s->name[1] == 'r') // originally an unnamed result + s = S; + else if(s->name[1] == 'b') // originally the blank identifier _ + s = lookup("_"); + } } else s = S; } @@ -1099,6 +1044,7 @@ static int opprec[] = { [OEMPTY] = -1, [OFALL] = -1, [OFOR] = -1, + [OGOTO] = -1, [OIF] = -1, [OLABEL] = -1, [OPROC] = -1, @@ -1163,7 +1109,10 @@ exprfmt(Fmt *f, Node *n, int prec) case PAUTO: case PPARAM: case PPARAMOUT: - if(fmtmode == FExp && n->sym && !isblanksym(n->sym) && n->vargen > 0) + // _ becomes ~b%d internally; print as _ for export + if(fmtmode == FExp && n->sym && n->sym->name[0] == '~' && n->sym->name[1] == 'b') + return fmtprint(f, "_"); + if(fmtmode == FExp && n->sym && !isblank(n) && n->vargen > 0) return fmtprint(f, "%S·%d", n->sym, n->vargen); } @@ -1390,7 +1339,6 @@ exprfmt(Fmt *f, Node *n, int prec) // Binary case OADD: - case OADDSTR: case OAND: case OANDAND: case OANDNOT: @@ -1415,6 +1363,14 @@ exprfmt(Fmt *f, Node *n, int prec) exprfmt(f, n->right, nprec+1); return 0; + case OADDSTR: + for(l=n->list; l; l=l->next) { + if(l != n->list) + fmtprint(f, " + "); + exprfmt(f, l->n, nprec); + } + return 0; + case OCMPSTR: case OCMPIFACE: exprfmt(f, n->left, nprec); @@ -1572,6 +1528,9 @@ Sconv(Fmt *fp) int r, sm; unsigned long sf; + if(fp->flags&FmtLong) + return linksymfmt(fp); + s = va_arg(fp->args, Sym*); if(s == S) return fmtstrcpy(fp, ""); diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c index ada16eacc..cf630f348 100644 --- a/src/cmd/gc/gen.c +++ b/src/cmd/gc/gen.c @@ -301,6 +301,9 @@ gen(Node *n) break; case OLABEL: + if(isblanksym(n->left->sym)) + break; + lab = newlab(n); // if there are pending gotos, resolve them all to the current pc. @@ -495,6 +498,11 @@ gen(Node *n) case OCHECKNIL: cgen_checknil(n->left); + break; + + case OVARKILL: + gvarkill(n->left); + break; } ret: @@ -562,8 +570,7 @@ cgen_proc(Node *n, int proc) /* * generate declaration. - * nothing to do for on-stack automatics, - * but might have to allocate heap copy + * have to allocate heap copy * for escaped variables. */ static void @@ -739,6 +746,8 @@ cgen_as(Node *nl, Node *nr) if(tl == T) return; if(isfat(tl)) { + if(nl->op == ONAME) + gvardef(nl); clearfat(nl); return; } @@ -767,10 +776,18 @@ cgen_eface(Node *n, Node *res) * so it's important that it is done first */ Node dst; + Node *tmp; + + tmp = temp(types[tptr]); + cgen(n->right, tmp); + + gvardef(res); + dst = *res; dst.type = types[tptr]; dst.xoffset += widthptr; - cgen(n->right, &dst); + cgen(tmp, &dst); + dst.xoffset -= widthptr; cgen(n->left, &dst); } @@ -787,7 +804,7 @@ cgen_eface(Node *n, Node *res) void cgen_slice(Node *n, Node *res) { - Node src, dst, *cap, *len, *offs, *add; + Node src, dst, *cap, *len, *offs, *add, *base; cap = n->list->n; len = n->list->next->n; @@ -795,24 +812,15 @@ cgen_slice(Node *n, Node *res) if(n->list->next->next) offs = n->list->next->next->n; - // dst.len = hi [ - lo ] - dst = *res; - dst.xoffset += Array_nel; - dst.type = types[simtype[TUINT]]; - cgen(len, &dst); - - if(n->op != OSLICESTR) { - // dst.cap = cap [ - lo ] - dst = *res; - dst.xoffset += Array_cap; - dst.type = types[simtype[TUINT]]; - cgen(cap, &dst); - } - - // dst.array = src.array [ + lo *width ] - dst = *res; - dst.xoffset += Array_array; - dst.type = types[TUINTPTR]; + // evaluate base pointer first, because it is the only + // possibly complex expression. once that is evaluated + // and stored, updating the len and cap can be done + // without making any calls, so without doing anything that + // might cause preemption or garbage collection. + // this makes the whole slice update atomic as far as the + // garbage collector can see. + + base = temp(types[TUINTPTR]); if(isnil(n->left)) { tempname(&src, n->left->type); @@ -821,24 +829,49 @@ cgen_slice(Node *n, Node *res) src = *n->left; if(n->op == OSLICE || n->op == OSLICE3 || n->op == OSLICESTR) src.xoffset += Array_array; - src.type = types[TUINTPTR]; if(n->op == OSLICEARR || n->op == OSLICE3ARR) { if(!isptr[n->left->type->etype]) fatal("slicearr is supposed to work on pointer: %+N\n", n); - cgen(&src, &dst); - cgen_checknil(&dst); + cgen(&src, base); + cgen_checknil(base); if(offs != N) { - add = nod(OADD, &dst, offs); + add = nod(OADD, base, offs); typecheck(&add, Erv); - cgen(add, &dst); + cgen(add, base); } } else if(offs == N) { - cgen(&src, &dst); + src.type = types[tptr]; + cgen(&src, base); } else { - add = nod(OADD, &src, offs); + src.type = types[tptr]; + add = nod(OADDPTR, &src, offs); typecheck(&add, Erv); - cgen(add, &dst); + cgen(add, base); + } + + // committed to the update + gvardef(res); + + // dst.array = src.array [ + lo *width ] + dst = *res; + dst.xoffset += Array_array; + dst.type = types[tptr]; + + cgen(base, &dst); + + // dst.len = hi [ - lo ] + dst = *res; + dst.xoffset += Array_nel; + dst.type = types[simtype[TUINT]]; + cgen(len, &dst); + + if(n->op != OSLICESTR) { + // dst.cap = cap [ - lo ] + dst = *res; + dst.xoffset += Array_cap; + dst.type = types[simtype[TUINT]]; + cgen(cap, &dst); } } @@ -935,5 +968,5 @@ temp(Type *t) n = nod(OXXX, N, N); tempname(n, t); n->sym->def->used = 1; - return n; + return n->orig; } diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index 562f16890..413e71069 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. #include +#include #undef OAPPEND @@ -31,7 +32,6 @@ enum STRINGSZ = 200, MAXALIGN = 7, UINF = 100, - HISTSZ = 10, PRIME1 = 3, @@ -129,6 +129,10 @@ struct Val } u; }; +// prevent incompatible type signatures between libgc and 8g on Plan 9 +#pragma incomplete struct Array + +typedef struct Array Array; typedef struct Bvec Bvec; typedef struct Pkg Pkg; typedef struct Sym Sym; @@ -190,6 +194,8 @@ struct Type // TMAP Type* bucket; // internal type representing a hash bucket Type* hmap; // internal type representing a Hmap (map header object) + Type* hiter; // internal type representing hash iterator state + Type* map; // link from the above 3 internal types back to the map type. int32 maplineno; // first use of TFORW as map key int32 embedlineno; // first use of TFORW as embedded type @@ -230,8 +236,10 @@ enum EscNone, EscReturn, EscNever, - EscBits = 4, + EscBits = 3, EscMask = (1<xoffset = block; } stmt_list { @@ -1730,6 +1731,7 @@ non_dcl_stmt: { // will be converted to OFALL $$ = nod(OXFALL, N, N); + $$->xoffset = block; } | LBREAK onew_name { @@ -2138,6 +2140,10 @@ hidden_literal: case CTFLT: mpnegflt($$->val.u.fval); break; + case CTCPLX: + mpnegflt(&$$->val.u.cval->real); + mpnegflt(&$$->val.u.cval->imag); + break; default: yyerror("bad negated constant"); } diff --git a/src/cmd/gc/inl.c b/src/cmd/gc/inl.c index 6800884a0..cf89b0090 100644 --- a/src/cmd/gc/inl.c +++ b/src/cmd/gc/inl.c @@ -392,6 +392,8 @@ inlnode(Node **np) case OCALLFUNC: case OCALLMETH: case OCALLINTER: + case OAPPEND: + case OCOMPLEX: // if we just replaced arg in f(arg()) or return arg with an inlined call // and arg returns multiple values, glue as list if(count(n->list) == 1 && n->list->n->op == OINLCALL && count(n->list->n->rlist) > 1) { @@ -800,6 +802,7 @@ inlvar(Node *var) n->class = PAUTO; n->used = 1; n->curfn = curfn; // the calling function, not the called one + n->addrtaken = var->addrtaken; // esc pass wont run if we're inlining into a iface wrapper // luckily, we can steal the results from the target func diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c index 8c739391a..a50101c42 100644 --- a/src/cmd/gc/lex.c +++ b/src/cmd/gc/lex.c @@ -14,7 +14,6 @@ #define ungetc ccungetc extern int yychar; -int windows; int yyprev; int yylast; @@ -61,7 +60,7 @@ static void addexp(char *s) { int i; - + for(i=0; exper[i].name != nil; i++) { if(strcmp(exper[i].name, s) == 0) { *exper[i].val = 1; @@ -78,8 +77,10 @@ setexp(void) { char *f[20]; int i, nf; - - // The makefile #defines GOEXPERIMENT for us. + + precisestack_enabled = 1; // on by default + + // cmd/dist #defines GOEXPERIMENT for us. nf = getfields(GOEXPERIMENT, f, nelem(f), 1, ","); for(i=0; i 0) + errorexit(); + fatal("fault"); + } + noted(NDFLT); +} +#endif + void doversion(void) { @@ -189,6 +205,24 @@ main(int argc, char *argv[]) signal(SIGSEGV, fault); #endif +#ifdef PLAN9 + notify(catcher); + // Tell the FPU to handle all exceptions. + setfcr(FPPDBL|FPRNR); +#endif + // Allow GOARCH=thestring or GOARCH=thestringsuffix, + // but not other values. + p = getgoarch(); + if(strncmp(p, thestring, strlen(thestring)) != 0) + sysfatal("cannot use %cg with GOARCH=%s", thechar, p); + goarch = p; + + linkarchinit(); + ctxt = linknew(thelinkarch); + ctxt->diag = yyerror; + ctxt->bso = &bstdout; + Binit(&bstdout, 1, OWRITE); + localpkg = mkpkg(strlit("")); localpkg->prefix = "\"\""; @@ -229,8 +263,11 @@ main(int argc, char *argv[]) goroot = getgoroot(); goos = getgoos(); - goarch = thestring; - + + nacl = strcmp(goos, "nacl") == 0; + if(nacl) + flag_largemodel = 1; + setexp(); outfile = nil; @@ -260,12 +297,16 @@ main(int argc, char *argv[]) flagstr("installsuffix", "pkg directory suffix", &flag_installsuffix); flagcount("j", "debug runtime-initialized variables", &debug['j']); flagcount("l", "disable inlining", &debug['l']); + flagcount("live", "debug liveness analysis", &debuglive); flagcount("m", "print optimization decisions", &debug['m']); + flagcount("nolocalimports", "reject local (relative) imports", &nolocalimports); flagstr("o", "obj: set output file", &outfile); flagstr("p", "path: set expected package import path", &myimportpath); + flagcount("pack", "write package file instead of object file", &writearchive); flagcount("r", "debug generated wrappers", &debug['r']); flagcount("race", "enable race detector", &flag_race); flagcount("s", "warn about composite literals that can be simplified", &debug['s']); + flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath); flagcount("u", "reject unsafe code", &safemode); flagcount("v", "increase debug verbosity", &debug['v']); flagcount("w", "debug type checking", &debug['w']); @@ -275,6 +316,7 @@ main(int argc, char *argv[]) flagcount("largemodel", "generate code that assumes a large memory model", &flag_largemodel); flagparse(&argc, &argv, usage); + ctxt->debugasm = debug['S']; if(argc < 1) usage(); @@ -319,20 +361,6 @@ main(int argc, char *argv[]) sysfatal("unsupported setting GO386=%s", p); } - pathname = mal(1000); - if(getwd(pathname, 999) == 0) - strcpy(pathname, "/???"); - - if(yy_isalpha(pathname[0]) && pathname[1] == ':') { - // On Windows. - windows = 1; - - // Canonicalize path by converting \ to / (Windows accepts both). - for(p=pathname; *p; p++) - if(*p == '\\') - *p = '/'; - } - fmtinstallgo(); betypeinit(); if(widthptr == 0) @@ -527,12 +555,13 @@ skiptopkgdef(Biobuf *b) return 0; if(memcmp(p, "!\n", 8) != 0) return 0; - /* symbol table is first; skip it */ + /* symbol table may be first; skip it */ sz = arsize(b, "__.GOSYMDEF"); - if(sz < 0) - return 0; - Bseek(b, sz, 1); - /* package export block is second */ + if(sz >= 0) + Bseek(b, sz, 1); + else + Bseek(b, 8, 0); + /* package export block is next */ sz = arsize(b, "__.PKGDEF"); if(sz <= 0) return 0; @@ -560,7 +589,7 @@ islocalname(Strlit *name) { if(name->len >= 1 && name->s[0] == '/') return 1; - if(windows && name->len >= 3 && + if(ctxt->windows && name->len >= 3 && yy_isalpha(name->s[0]) && name->s[1] == ':' && name->s[2] == '/') return 1; if(name->len >= 2 && strncmp(name->s, "./", 2) == 0) @@ -581,7 +610,7 @@ findpkg(Strlit *name) char *q, *suffix, *suffixsep; if(islocalname(name)) { - if(safemode) + if(safemode || nolocalimports) return 0; // try .a before .6. important for building libraries: // if there is an array.6 in the array.a library, @@ -702,7 +731,7 @@ importfile(Val *f, int line) fakeimport(); return; } - prefix = pathname; + prefix = ctxt->pathname; if(localimport != nil) prefix = localimport; cleanbuf = mal(strlen(prefix) + strlen(path->s) + 2); @@ -760,7 +789,7 @@ importfile(Val *f, int line) yyerror("import %s: not a go object file", file); errorexit(); } - q = smprint("%s %s %s %s", getgoos(), thestring, getgoversion(), expstring()); + q = smprint("%s %s %s %s", getgoos(), getgoarch(), getgoversion(), expstring()); if(strcmp(p+10, q) != 0) { yyerror("import %s: object is [%s] expected [%s]", file, p+10, q); errorexit(); @@ -1528,7 +1557,7 @@ getlinepragma(void) goto out; // try to avoid allocating file name over and over - for(h=hist; h!=H; h=h->link) { + for(h=ctxt->hist; h!=nil; h=h->link) { if(h->name != nil && strcmp(h->name, lexbuf) == 0) { linehist(h->name, n, 0); goto out; @@ -2143,14 +2172,18 @@ struct } lexn[] = { LANDAND, "ANDAND", + LANDNOT, "ANDNOT", LASOP, "ASOP", LBREAK, "BREAK", LCASE, "CASE", LCHAN, "CHAN", LCOLAS, "COLAS", + LCOMM, "<-", LCONST, "CONST", LCONTINUE, "CONTINUE", + LDDD, "...", LDEC, "DEC", + LDEFAULT, "DEFAULT", LDEFER, "DEFER", LELSE, "ELSE", LEQ, "EQ", @@ -2177,6 +2210,7 @@ struct LRANGE, "RANGE", LRETURN, "RETURN", LRSH, "RSH", + LSELECT, "SELECT", LSTRUCT, "STRUCT", LSWITCH, "SWITCH", LTYPE, "TYPE", @@ -2207,6 +2241,7 @@ struct "LASOP", "op=", "LBREAK", "break", "LCASE", "case", + "LCHAN", "chan", "LCOLAS", ":=", "LCONST", "const", "LCONTINUE", "continue", @@ -2354,7 +2389,7 @@ mkpackage(char* pkgname) if(outfile == nil) { p = strrchr(infile, '/'); - if(windows) { + if(ctxt->windows) { q = strrchr(infile, '\\'); if(q > p) p = q; diff --git a/src/cmd/gc/md5.c b/src/cmd/gc/md5.c index bbd4e298f..0051ac964 100644 --- a/src/cmd/gc/md5.c +++ b/src/cmd/gc/md5.c @@ -63,7 +63,7 @@ md5write(MD5 *d, uchar *p, int nn) } uint64 -md5sum(MD5 *d) +md5sum(MD5 *d, uint64 *hi) { uchar tmp[64]; int i; @@ -87,6 +87,8 @@ md5sum(MD5 *d) if(d->nx != 0) fatal("md5sum"); + if(hi != nil) + *hi = d->s[2] | ((uint64)d->s[3]<<32); return d->s[0] | ((uint64)d->s[1]<<32); } diff --git a/src/cmd/gc/md5.h b/src/cmd/gc/md5.h index f153e30f2..5a60106b2 100644 --- a/src/cmd/gc/md5.h +++ b/src/cmd/gc/md5.h @@ -13,4 +13,4 @@ struct MD5 void md5reset(MD5*); void md5write(MD5*, uchar*, int); -uint64 md5sum(MD5*); +uint64 md5sum(MD5*, uint64*); diff --git a/src/cmd/gc/mparith1.c b/src/cmd/gc/mparith1.c index e25044a8b..1519caec7 100644 --- a/src/cmd/gc/mparith1.c +++ b/src/cmd/gc/mparith1.c @@ -65,7 +65,7 @@ mpcmpfltc(Mpflt *b, double c) Mpflt a; mpmovecflt(&a, c); - return mpcmpfltflt(&a, b); + return mpcmpfltflt(b, &a); } void @@ -416,7 +416,7 @@ mpatoflt(Mpflt *a, char *as) if(eb) { if(dp) goto bad; - a->exp += ex; + mpsetexp(a, a->exp+ex); goto out; } @@ -427,8 +427,14 @@ mpatoflt(Mpflt *a, char *as) mppow10flt(&b, ex-dp); mpmulfltflt(a, &b); } else { - mppow10flt(&b, dp-ex); - mpdivfltflt(a, &b); + // 4 approximates least_upper_bound(log2(10)). + if(dp-ex >= (1<<(8*sizeof(dp)-3)) || (short)(4*(dp-ex)) != 4*(dp-ex)) { + mpmovecflt(a, 0.0); + } + else { + mppow10flt(&b, dp-ex); + mpdivfltflt(a, &b); + } } } @@ -573,20 +579,40 @@ Fconv(Fmt *fp) { char buf[500]; Mpflt *fvp, fv; - double d; + double d, dexp; + int exp; fvp = va_arg(fp->args, Mpflt*); if(fp->flags & FmtSharp) { // alternate form - decimal for error messages. // for well in range, convert to double and use print's %g - if(-900 < fvp->exp && fvp->exp < 900) { + exp = fvp->exp + sigfig(fvp)*Mpscale; + if(-900 < exp && exp < 900) { d = mpgetflt(fvp); if(d >= 0 && (fp->flags & FmtSign)) fmtprint(fp, "+"); - return fmtprint(fp, "%g", d); + return fmtprint(fp, "%g", d, exp, fvp); + } + + // very out of range. compute decimal approximation by hand. + // decimal exponent + dexp = fvp->exp * 0.301029995663981195; // log_10(2) + exp = (int)dexp; + // decimal mantissa + fv = *fvp; + fv.val.neg = 0; + fv.exp = 0; + d = mpgetflt(&fv); + d *= pow(10, dexp-exp); + while(d >= 9.99995) { + d /= 10; + exp++; } - // TODO(rsc): for well out of range, print - // an approximation like 1.234e1000 + if(fvp->val.neg) + fmtprint(fp, "-"); + else if(fp->flags & FmtSign) + fmtprint(fp, "+"); + return fmtprint(fp, "%.5fe+%d", d, exp); } if(sigfig(fvp) == 0) { diff --git a/src/cmd/gc/mparith2.c b/src/cmd/gc/mparith2.c index 9b2f664f7..5cf98c62c 100644 --- a/src/cmd/gc/mparith2.c +++ b/src/cmd/gc/mparith2.c @@ -300,13 +300,21 @@ mpmulfixfix(Mpint *a, Mpint *b) for(i=0; i>= 1; } } +out: q.neg = a->neg ^ b->neg; mpmovefixfix(a, &q); if(a->ovf) diff --git a/src/cmd/gc/mparith3.c b/src/cmd/gc/mparith3.c index f8344c9b4..95618f1c6 100644 --- a/src/cmd/gc/mparith3.c +++ b/src/cmd/gc/mparith3.c @@ -22,6 +22,27 @@ sigfig(Mpflt *a) return i+1; } +/* + * sets the exponent. + * a too large exponent is an error. + * a too small exponent rounds the number to zero. + */ +void +mpsetexp(Mpflt *a, int exp) { + if((short)exp != exp) { + if(exp > 0) { + yyerror("float constant is too large"); + a->exp = 0x7fff; + } + else { + mpmovecflt(a, 0); + } + } + else { + a->exp = exp; + } +} + /* * shifts the leading non-zero * word of the number to Mpnorm @@ -60,7 +81,7 @@ mpnorm(Mpflt *a) } mpshiftfix(&a->val, s); - a->exp -= s; + mpsetexp(a, a->exp-s); } /// implements float arihmetic @@ -95,7 +116,7 @@ mpaddfltflt(Mpflt *a, Mpflt *b) if(s < 0) { // b is larger, shift a right mpshiftfix(&a->val, s); - a->exp -= s; + mpsetexp(a, a->exp-s); mpaddfixfix(&a->val, &b->val, 0); goto out; } @@ -131,7 +152,7 @@ mpmulfltflt(Mpflt *a, Mpflt *b) } mpmulfract(&a->val, &b->val); - a->exp = (a->exp + b->exp) + Mpscale*Mpprec - Mpscale - 1; + mpsetexp(a, (a->exp + b->exp) + Mpscale*Mpprec - Mpscale - 1); mpnorm(a); if(Mpdebug) @@ -171,18 +192,18 @@ mpdivfltflt(Mpflt *a, Mpflt *b) // divide mpdivfract(&a->val, &c.val); - a->exp = (a->exp-c.exp) - Mpscale*(Mpprec-1) + 1; + mpsetexp(a, (a->exp-c.exp) - Mpscale*(Mpprec-1) + 1); mpnorm(a); if(Mpdebug) print(" = %F\n\n", a); } -double -mpgetflt(Mpflt *a) +static double +mpgetfltN(Mpflt *a, int prec, int bias) { - int s, i, e; - uvlong v, vm; + int s, i, e, minexp; + uvlong v; double f; if(a->val.ovf && nsavederrors+nerrors == 0) @@ -199,59 +220,69 @@ mpgetflt(Mpflt *a) while((a->val.a[Mpnorm-1] & Mpsign) == 0) { mpshiftfix(&a->val, 1); - a->exp -= 1; + mpsetexp(a, a->exp-1); // can set 'a' to zero + s = sigfig(a); + if(s == 0) + return 0; } - // the magic numbers (64, 63, 53, 10, -1074) are - // IEEE specific. this should be done machine - // independently or in the 6g half of the compiler - - // pick up the mantissa and a rounding bit in a uvlong - s = 53+1; + // pick up the mantissa, a rounding bit, and a tie-breaking bit in a uvlong + s = prec+2; v = 0; for(i=Mpnorm-1; s>=Mpscale; i--) { v = (v<val.a[i]; s -= Mpscale; } - vm = v; - if(s > 0) - vm = (vm<val.a[i]>>(Mpscale-s)); - - // continue with 64 more bits - s += 64; - for(; s>=Mpscale; i--) { - v = (v<val.a[i]; - s -= Mpscale; - } - if(s > 0) + if(s > 0) { v = (v<val.a[i]>>(Mpscale-s)); + if((a->val.a[i]&((1<<(Mpscale-s))-1)) != 0) + v |= 1; + i--; + } + for(; i >= 0; i--) { + if(a->val.a[i] != 0) + v |= 1; + } // gradual underflow - e = Mpnorm*Mpscale + a->exp - 53; - if(e < -1074) { - s = -e - 1074; - if(s > 54) - s = 54; - v |= vm & ((1ULL<>= s; - e = -1074; + e = Mpnorm*Mpscale + a->exp - prec; + minexp = bias+1-prec+1; + if(e < minexp) { + s = minexp - e; + if(s > prec+1) + s = prec+1; + if((v & ((1<>= s; + e = minexp; } + + // round to even + v |= (v&4)>>2; + v += v&1; + v >>= 2; -//print("vm=%.16llux v=%.16llux\n", vm, v); - // round toward even - if(v != 0 || (vm&2ULL) != 0) - vm = (vm>>1) + (vm&1ULL); - else - vm >>= 1; - - f = (double)(vm); + f = (double)(v); f = ldexp(f, e); if(a->val.neg) f = -f; + return f; } +double +mpgetflt(Mpflt *a) +{ + return mpgetfltN(a, 53, -1023); +} + +double +mpgetflt32(Mpflt *a) +{ + return mpgetfltN(a, 24, -127); +} + void mpmovecflt(Mpflt *a, double c) { diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c index 4cad08924..4eeb03aa8 100644 --- a/src/cmd/gc/obj.c +++ b/src/cmd/gc/obj.c @@ -10,13 +10,28 @@ * architecture-independent object file output */ -static void outhist(Biobuf *b); static void dumpglobls(void); +enum +{ + ArhdrSize = 60 +}; + +static void +formathdr(char *arhdr, char *name, vlong size) +{ + snprint(arhdr, ArhdrSize, "%-16s%-12d%-6d%-6d%-8o%-10lld`", + name, 0, 0, 0, 0644, size); + arhdr[ArhdrSize-1] = '\n'; // overwrite \0 written by snprint +} + void dumpobj(void) { NodeList *externs, *tmp; + char arhdr[ArhdrSize]; + vlong startobj, size; + Sym *zero; bout = Bopen(outfile, OWRITE); if(bout == nil) { @@ -25,13 +40,34 @@ dumpobj(void) errorexit(); } - Bprint(bout, "go object %s %s %s %s\n", getgoos(), thestring, getgoversion(), expstring()); - Bprint(bout, " exports automatically generated from\n"); - Bprint(bout, " %s in package \"%s\"\n", curio.infile, localpkg->name); + startobj = 0; + if(writearchive) { + Bwrite(bout, "!\n", 8); + memset(arhdr, 0, sizeof arhdr); + Bwrite(bout, arhdr, sizeof arhdr); + startobj = Boffset(bout); + } + Bprint(bout, "go object %s %s %s %s\n", getgoos(), getgoarch(), getgoversion(), expstring()); dumpexport(); - Bprint(bout, "\n!\n"); + + if(writearchive) { + Bflush(bout); + size = Boffset(bout) - startobj; + if(size&1) + Bputc(bout, 0); + Bseek(bout, startobj - ArhdrSize, 0); + formathdr(arhdr, "__.PKGDEF", size); + Bwrite(bout, arhdr, ArhdrSize); + Bflush(bout); + + Bseek(bout, startobj + size + (size&1), 0); + memset(arhdr, 0, ArhdrSize); + Bwrite(bout, arhdr, ArhdrSize); + startobj = Boffset(bout); + Bprint(bout, "go object %s %s %s %s\n", getgoos(), getgoarch(), getgoversion(), expstring()); + } - outhist(bout); + Bprint(bout, "\n!\n"); externs = nil; if(externdcl != nil) @@ -47,9 +83,22 @@ dumpobj(void) dumpglobls(); externdcl = tmp; - dumpdata(); - dumpfuncs(); + zero = pkglookup("zerovalue", runtimepkg); + ggloblsym(zero, zerosize, 1, 1); + dumpdata(); + writeobj(ctxt, bout); + + if(writearchive) { + Bflush(bout); + size = Boffset(bout) - startobj; + if(size&1) + Bputc(bout, 0); + Bseek(bout, startobj - ArhdrSize, 0); + snprint(namebuf, sizeof namebuf, "_go_.%c", thechar); + formathdr(arhdr, namebuf, size); + Bwrite(bout, arhdr, ArhdrSize); + } Bterm(bout); } @@ -75,184 +124,50 @@ dumpglobls(void) ggloblnod(n); } - + for(l=funcsyms; l; l=l->next) { n = l->n; dsymptr(n->sym, 0, n->sym->def->shortname->sym, 0); ggloblsym(n->sym, widthptr, 1, 1); } + + // Do not reprocess funcsyms on next dumpglobls call. + funcsyms = nil; } void -Bputname(Biobuf *b, Sym *s) +Bputname(Biobuf *b, LSym *s) { - Bprint(b, "%s", s->pkg->prefix); - BPUTC(b, '.'); Bwrite(b, s->name, strlen(s->name)+1); } -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) +LSym* +linksym(Sym *s) { - 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); + char *p; + + if(s == nil) + return nil; + if(s->lsym != nil) + return s->lsym; + if(isblanksym(s)) + s->lsym = linklookup(ctxt, "_", 0); + else { + p = smprint("%s.%s", s->pkg->prefix, s->name); + s->lsym = linklookup(ctxt, p, 0); + free(p); } + return s->lsym; } -static void -outhist(Biobuf *b) -{ - Hist *h; - char *p, ds[] = {'c', ':', '/', 0}; - char *tofree; - int n; - static int first = 1; - static char *goroot, *goroot_final; - - if(first) { - // Decide whether we need to rewrite paths from $GOROOT to $GOROOT_FINAL. - first = 0; - goroot = getenv("GOROOT"); - goroot_final = getenv("GOROOT_FINAL"); - if(goroot == nil) - goroot = ""; - if(goroot_final == nil) - goroot_final = goroot; - if(strcmp(goroot, goroot_final) == 0) { - goroot = nil; - goroot_final = nil; - } - } - - tofree = nil; - for(h = hist; h != H; h = h->link) { - p = h->name; - if(p) { - if(goroot != nil) { - n = strlen(goroot); - if(strncmp(p, goroot, strlen(goroot)) == 0 && p[n] == '/') { - tofree = smprint("%s%s", goroot_final, p+n); - p = tofree; - } - } - 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 { - 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); - if(tofree) { - free(tofree); - tofree = nil; - } - } -} - -void -ieeedtod(uint64 *ieee, double native) +int +duintxx(Sym *s, int off, uint64 v, int wid) { - double fr, ho, f; - int exp; - uint32 h, l; - uint64 bits; - - if(native < 0) { - ieeedtod(ieee, -native); - *ieee |= 1ULL<<63; - return; - } - if(native == 0) { - *ieee = 0; - return; - } - fr = frexp(native, &exp); - f = 2097152L; /* shouldn't use fp constants here */ - fr = modf(fr*f, &ho); - h = ho; - h &= 0xfffffL; - f = 65536L; - fr = modf(fr*f, &ho); - l = ho; - l <<= 16; - l |= (int32)(fr*f); - bits = ((uint64)h<<32) | l; - if(exp < -1021) { - // gradual underflow - bits |= 1LL<<52; - bits >>= -1021 - exp; - exp = -1022; - } - bits |= (uint64)(exp+1022L) << 52; - *ieee = bits; + // Update symbol data directly instead of generating a + // DATA instruction that liblink will have to interpret later. + // This reduces compilation time and memory usage. + off = rnd(off, wid); + return setuintxx(ctxt, linksym(s), off, v, wid); } int @@ -338,3 +253,31 @@ stringsym(char *s, int len) return sym; } + +void +slicebytes(Node *nam, char *s, int len) +{ + int off, n, m; + static int gen; + Sym *sym; + + snprint(namebuf, sizeof(namebuf), ".gobytes.%d", ++gen); + sym = pkglookup(namebuf, localpkg); + sym->def = newname(sym); + + off = 0; + for(n=0; n len-n) + m = len-n; + off = dsname(sym, off, s+n, m); + } + ggloblsym(sym, off, 0, 0); + + if(nam->op != ONAME) + fatal("slicebytes %N", nam); + off = nam->xoffset; + off = dsymptr(nam->sym, off, sym, 0); + off = duintxx(nam->sym, off, len, widthint); + duintxx(nam->sym, off, len, widthint); +} diff --git a/src/cmd/gc/order.c b/src/cmd/gc/order.c index 7552510e9..30dbc7dac 100644 --- a/src/cmd/gc/order.c +++ b/src/cmd/gc/order.c @@ -5,79 +5,343 @@ // Rewrite tree to use separate statements to enforce // order of evaluation. Makes walk easier, because it // can (after this runs) reorder at will within an expression. +// +// Rewrite x op= y into x = x op y. +// +// Introduce temporaries as needed by runtime routines. +// For example, the map runtime routines take the map key +// by reference, so make sure all map keys are addressable +// by copying them to temporaries as needed. +// The same is true for channel operations. +// +// Arrange that map index expressions only appear in direct +// assignments x = m[k] or m[k] = x, never in larger expressions. +// +// Arrange that receive expressions only appear in direct assignments +// x = <-c or as standalone statements <-c, never in larger expressions. + +// TODO(rsc): The temporary introduction during multiple assignments +// should be moved into this file, so that the temporaries can be cleaned +// and so that conversions implicit in the OAS2FUNC and OAS2RECV +// nodes can be made explicit and then have their temporaries cleaned. + +// TODO(rsc): Goto and multilevel break/continue can jump over +// inserted VARKILL annotations. Work out a way to handle these. +// The current implementation is safe, in that it will execute correctly. +// But it won't reuse temporaries as aggressively as it might, and +// it can result in unnecessary zeroing of those variables in the function +// prologue. #include #include #include "go.h" -static void orderstmt(Node*, NodeList**); -static void orderstmtlist(NodeList*, NodeList**); +// Order holds state during the ordering process. +typedef struct Order Order; +struct Order +{ + NodeList *out; // list of generated statements + NodeList *temp; // head of stack of temporary variables + NodeList *free; // free list of NodeList* structs (for use in temp) +}; + +static void orderstmt(Node*, Order*); +static void orderstmtlist(NodeList*, Order*); static void orderblock(NodeList **l); -static void orderexpr(Node**, NodeList**); -static void orderexprlist(NodeList*, NodeList**); +static void orderexpr(Node**, Order*); +static void orderexprinplace(Node**, Order*); +static void orderexprlist(NodeList*, Order*); +static void orderexprlistinplace(NodeList*, Order*); +// Order rewrites fn->nbody to apply the ordering constraints +// described in the comment at the top of the file. void order(Node *fn) { orderblock(&fn->nbody); } +// Ordertemp allocates a new temporary with the given type, +// pushes it onto the temp stack, and returns it. +// If clear is true, ordertemp emits code to zero the temporary. +static Node* +ordertemp(Type *t, Order *order, int clear) +{ + Node *var, *a; + NodeList *l; + + var = temp(t); + if(clear) { + a = nod(OAS, var, N); + typecheck(&a, Etop); + order->out = list(order->out, a); + } + if((l = order->free) == nil) + l = mal(sizeof *l); + order->free = l->next; + l->next = order->temp; + l->n = var; + order->temp = l; + return var; +} + +// Ordercopyexpr behaves like ordertemp but also emits +// code to initialize the temporary to the value n. +// +// The clear argument is provided for use when the evaluation +// of tmp = n turns into a function call that is passed a pointer +// to the temporary as the output space. If the call blocks before +// tmp has been written, the garbage collector will still treat the +// temporary as live, so we must zero it before entering that call. +// Today, this only happens for channel receive operations. +// (The other candidate would be map access, but map access +// returns a pointer to the result data instead of taking a pointer +// to be filled in.) +static Node* +ordercopyexpr(Node *n, Type *t, Order *order, int clear) +{ + Node *a, *var; + + var = ordertemp(t, order, clear); + a = nod(OAS, var, n); + typecheck(&a, Etop); + order->out = list(order->out, a); + return var; +} + +// Ordercheapexpr returns a cheap version of n. +// The definition of cheap is that n is a variable or constant. +// If not, ordercheapexpr allocates a new tmp, emits tmp = n, +// and then returns tmp. +static Node* +ordercheapexpr(Node *n, Order *order) +{ + switch(n->op) { + case ONAME: + case OLITERAL: + return n; + } + return ordercopyexpr(n, n->type, order, 0); +} + +// Ordersafeexpr returns a safe version of n. +// The definition of safe is that n can appear multiple times +// without violating the semantics of the original program, +// and that assigning to the safe version has the same effect +// as assigning to the original n. +// +// The intended use is to apply to x when rewriting x += y into x = x + y. +static Node* +ordersafeexpr(Node *n, Order *order) +{ + Node *l, *r, *a; + + switch(n->op) { + default: + fatal("ordersafeexpr %O", n->op); + + case ONAME: + case OLITERAL: + return n; + + case ODOT: + l = ordersafeexpr(n->left, order); + if(l == n->left) + return n; + a = nod(OXXX, N, N); + *a = *n; + a->orig = a; + a->left = l; + typecheck(&a, Erv); + return a; + + case ODOTPTR: + case OIND: + l = ordercheapexpr(n->left, order); + if(l == n->left) + return n; + a = nod(OXXX, N, N); + *a = *n; + a->orig = a; + a->left = l; + typecheck(&a, Erv); + return a; + + case OINDEX: + case OINDEXMAP: + if(isfixedarray(n->left->type)) + l = ordersafeexpr(n->left, order); + else + l = ordercheapexpr(n->left, order); + r = ordercheapexpr(n->right, order); + if(l == n->left && r == n->right) + return n; + a = nod(OXXX, N, N); + *a = *n; + a->orig = a; + a->left = l; + a->right = r; + typecheck(&a, Erv); + return a; + } +} + +// Istemp reports whether n is a temporary variable. +static int +istemp(Node *n) +{ + if(n->op != ONAME) + return 0; + return strncmp(n->sym->name, "autotmp_", 8) == 0; +} + +// Isaddrokay reports whether it is okay to pass n's address to runtime routines. +// Taking the address of a variable makes the liveness and optimization analyses +// lose track of where the variable's lifetime ends. To avoid hurting the analyses +// of ordinary stack variables, those are not 'isaddrokay'. Temporaries are okay, +// because we emit explicit VARKILL instructions marking the end of those +// temporaries' lifetimes. +static int +isaddrokay(Node *n) +{ + return islvalue(n) && (n->op != ONAME || n->class == PEXTERN || istemp(n)); +} + +// Orderaddrtemp ensures that *np is okay to pass by address to runtime routines. +// If the original argument *np is not okay, orderaddrtemp creates a tmp, emits +// tmp = *np, and then sets *np to the tmp variable. static void -orderstmtlist(NodeList *l, NodeList **out) +orderaddrtemp(Node **np, Order *order) +{ + Node *n; + + n = *np; + if(isaddrokay(n)) + return; + *np = ordercopyexpr(n, n->type, order, 0); +} + +// Marktemp returns the top of the temporary variable stack. +static NodeList* +marktemp(Order *order) +{ + return order->temp; +} + +// Poptemp pops temporaries off the stack until reaching the mark, +// which must have been returned by marktemp. +static void +poptemp(NodeList *mark, Order *order) +{ + NodeList *l; + + while((l = order->temp) != mark) { + order->temp = l->next; + l->next = order->free; + order->free = l; + } +} + +// Cleantempnopop emits to *out VARKILL instructions for each temporary +// above the mark on the temporary stack, but it does not pop them +// from the stack. +static void +cleantempnopop(NodeList *mark, Order *order, NodeList **out) +{ + NodeList *l; + Node *kill; + + for(l=order->temp; l != mark; l=l->next) { + kill = nod(OVARKILL, l->n, N); + typecheck(&kill, Etop); + *out = list(*out, kill); + } +} + +// Cleantemp emits VARKILL instructions for each temporary above the +// mark on the temporary stack and removes them from the stack. +static void +cleantemp(NodeList *top, Order *order) +{ + cleantempnopop(top, order, &order->out); + poptemp(top, order); +} + +// Orderstmtlist orders each of the statements in the list. +static void +orderstmtlist(NodeList *l, Order *order) { for(; l; l=l->next) - orderstmt(l->n, out); + orderstmt(l->n, order); } -// Order the block of statements *l onto a new list, -// and then replace *l with that list. +// Orderblock orders the block of statements *l onto a new list, +// and then replaces *l with that list. static void orderblock(NodeList **l) { - NodeList *out; + Order order; + NodeList *mark; - out = nil; - orderstmtlist(*l, &out); - *l = out; + memset(&order, 0, sizeof order); + mark = marktemp(&order); + orderstmtlist(*l, &order); + cleantemp(mark, &order); + *l = order.out; } -// Order the side effects in *np and leave them as -// the init list of the final *np. +// Orderexprinplace orders the side effects in *np and +// leaves them as the init list of the final *np. static void -orderexprinplace(Node **np) +orderexprinplace(Node **np, Order *outer) { Node *n; - NodeList *out; + NodeList **lp; + Order order; n = *np; - out = nil; - orderexpr(&n, &out); - addinit(&n, out); + memset(&order, 0, sizeof order); + orderexpr(&n, &order); + addinit(&n, order.out); + + // insert new temporaries from order + // at head of outer list. + lp = &order.temp; + while(*lp != nil) + lp = &(*lp)->next; + *lp = outer->temp; + outer->temp = order.temp; + *np = n; } -// Like orderblock, but applied to a single statement. +// Orderstmtinplace orders the side effects of the single statement *np +// and replaces it with the resulting statement list. static void orderstmtinplace(Node **np) { Node *n; - NodeList *out; - + Order order; + NodeList *mark; + n = *np; - out = nil; - orderstmt(n, &out); - *np = liststmt(out); + memset(&order, 0, sizeof order); + mark = marktemp(&order); + orderstmt(n, &order); + cleantemp(mark, &order); + *np = liststmt(order.out); } -// Move n's init list to *out. +// Orderinit moves n's init list to order->out. static void -orderinit(Node *n, NodeList **out) +orderinit(Node *n, Order *order) { - orderstmtlist(n->ninit, out); + orderstmtlist(n->ninit, order); n->ninit = nil; } -// Is the list l actually just f() for a multi-value function? +// Ismulticall reports whether the list l is f() for a multi-value function. +// Such an f() could appear as the lone argument to a multi-arg function. static int ismulticall(NodeList *l) { @@ -102,10 +366,10 @@ ismulticall(NodeList *l) return n->left->type->outtuple > 1; } -// n is a multi-value function call. Add t1, t2, .. = n to out -// and return the list t1, t2, ... +// Copyret emits t1, t2, ... = n, where n is a function call, +// and then returns the list t1, t2, .... static NodeList* -copyret(Node *n, NodeList **out) +copyret(Node *n, Order *order) { Type *t; Node *tmp, *as; @@ -127,86 +391,224 @@ copyret(Node *n, NodeList **out) as->list = l1; as->rlist = list1(n); typecheck(&as, Etop); - orderstmt(as, out); + orderstmt(as, order); return l2; } +// Ordercallargs orders the list of call arguments *l. static void -ordercallargs(NodeList **l, NodeList **out) +ordercallargs(NodeList **l, Order *order) { if(ismulticall(*l)) { // return f() where f() is multiple values. - *l = copyret((*l)->n, out); + *l = copyret((*l)->n, order); } else { - orderexprlist(*l, out); + orderexprlist(*l, order); } } +// Ordercall orders the call expression n. +// n->op is OCALLMETH/OCALLFUNC/OCALLINTER or a builtin like OCOPY. static void -ordercall(Node *n, NodeList **out) +ordercall(Node *n, Order *order) { - orderexpr(&n->left, out); - ordercallargs(&n->list, out); + orderexpr(&n->left, order); + orderexpr(&n->right, order); // ODDDARG temp + ordercallargs(&n->list, order); } +// Ordermapassign appends n to order->out, introducing temporaries +// to make sure that all map assignments have the form m[k] = x, +// where x is adressable. +// (Orderexpr has already been called on n, so we know k is addressable.) +// +// If n is m[k] = x where x is not addressable, the rewrite is: +// tmp = x +// m[k] = tmp +// +// If n is the multiple assignment form ..., m[k], ... = ..., the rewrite is +// t1 = m +// t2 = k +// ...., t3, ... = x +// t1[t2] = t3 +// +// The temporaries t1, t2 are needed in case the ... being assigned +// contain m or k. They are usually unnecessary, but in the unnecessary +// cases they are also typically registerizable, so not much harm done. +// And this only applies to the multiple-assignment form. +// We could do a more precise analysis if needed, like in walk.c. static void -orderstmt(Node *n, NodeList **out) +ordermapassign(Node *n, Order *order) { - int lno; + Node *m, *a; NodeList *l; - Node *r; + NodeList *post; + + switch(n->op) { + default: + fatal("ordermapassign %O", n->op); + + case OAS: + order->out = list(order->out, n); + if(n->left->op == OINDEXMAP && !isaddrokay(n->right)) { + m = n->left; + n->left = ordertemp(m->type, order, 0); + a = nod(OAS, m, n->left); + typecheck(&a, Etop); + order->out = list(order->out, a); + } + break; + + case OAS2: + case OAS2DOTTYPE: + case OAS2MAPR: + case OAS2FUNC: + post = nil; + for(l=n->list; l != nil; l=l->next) { + if(l->n->op == OINDEXMAP) { + m = l->n; + if(!istemp(m->left)) + m->left = ordercopyexpr(m->left, m->left->type, order, 0); + if(!istemp(m->right)) + m->right = ordercopyexpr(m->right, m->right->type, order, 0); + l->n = ordertemp(m->type, order, 0); + a = nod(OAS, m, l->n); + typecheck(&a, Etop); + post = list(post, a); + } + } + order->out = list(order->out, n); + order->out = concat(order->out, post); + break; + } +} + +// Orderstmt orders the statement n, appending to order->out. +// Temporaries created during the statement are cleaned +// up using VARKILL instructions as possible. +static void +orderstmt(Node *n, Order *order) +{ + int lno; + NodeList *l, *t, *t1; + Node *r, *tmp1, *tmp2, **np; + Type *ch; if(n == N) return; lno = setlineno(n); - orderinit(n, out); + orderinit(n, order); switch(n->op) { default: fatal("orderstmt %O", n->op); + case OVARKILL: + order->out = list(order->out, n); + break; + + case OAS: case OAS2: case OAS2DOTTYPE: - case OAS2MAPR: - case OAS: - case OASOP: case OCLOSE: case OCOPY: - case ODELETE: - case OPANIC: case OPRINT: case OPRINTN: case ORECOVER: case ORECV: - case OSEND: - orderexpr(&n->left, out); - orderexpr(&n->right, out); - orderexprlist(n->list, out); - orderexprlist(n->rlist, out); - *out = list(*out, n); + t = marktemp(order); + orderexpr(&n->left, order); + orderexpr(&n->right, order); + orderexprlist(n->list, order); + orderexprlist(n->rlist, order); + switch(n->op) { + case OAS: + case OAS2: + case OAS2DOTTYPE: + ordermapassign(n, order); + break; + default: + order->out = list(order->out, n); + break; + } + cleantemp(t, order); break; - + + case OASOP: + // Special: rewrite l op= r into l = l op r. + // This simplies quite a few operations; + // most important is that it lets us separate + // out map read from map write when l is + // a map index expression. + t = marktemp(order); + orderexpr(&n->left, order); + n->left = ordersafeexpr(n->left, order); + tmp1 = treecopy(n->left); + if(tmp1->op == OINDEXMAP) + tmp1->etype = 0; // now an rvalue not an lvalue + tmp1 = ordercopyexpr(tmp1, n->left->type, order, 0); + n->right = nod(n->etype, tmp1, n->right); + typecheck(&n->right, Erv); + orderexpr(&n->right, order); + n->etype = 0; + n->op = OAS; + ordermapassign(n, order); + cleantemp(t, order); + break; + + case OAS2MAPR: + // Special: make sure key is addressable, + // and make sure OINDEXMAP is not copied out. + t = marktemp(order); + orderexprlist(n->list, order); + r = n->rlist->n; + orderexpr(&r->left, order); + orderexpr(&r->right, order); + // See case OINDEXMAP below. + if(r->right->op == OARRAYBYTESTR) + r->right->op = OARRAYBYTESTRTMP; + orderaddrtemp(&r->right, order); + ordermapassign(n, order); + cleantemp(t, order); + break; + case OAS2FUNC: // Special: avoid copy of func call n->rlist->n. - orderexprlist(n->list, out); - ordercall(n->rlist->n, out); - *out = list(*out, n); + t = marktemp(order); + orderexprlist(n->list, order); + ordercall(n->rlist->n, order); + ordermapassign(n, order); + cleantemp(t, order); break; case OAS2RECV: // Special: avoid copy of receive. - orderexprlist(n->list, out); - orderexpr(&n->rlist->n->left, out); // arg to recv - *out = list(*out, n); + // Use temporary variables to hold result, + // so that chanrecv can take address of temporary. + t = marktemp(order); + orderexprlist(n->list, order); + orderexpr(&n->rlist->n->left, order); // arg to recv + ch = n->rlist->n->left->type; + tmp1 = ordertemp(ch->type, order, haspointers(ch->type)); + tmp2 = ordertemp(types[TBOOL], order, 0); + order->out = list(order->out, n); + r = nod(OAS, n->list->n, tmp1); + typecheck(&r, Etop); + ordermapassign(r, order); + r = nod(OAS, n->list->next->n, tmp2); + typecheck(&r, Etop); + ordermapassign(r, order); + n->list = list(list1(tmp1), tmp2); + cleantemp(t, order); break; case OBLOCK: case OEMPTY: // Special: does not save n onto out. - orderstmtlist(n->list, out); + orderstmtlist(n->list, order); break; case OBREAK: @@ -215,109 +617,329 @@ orderstmt(Node *n, NodeList **out) case ODCLCONST: case ODCLTYPE: case OFALL: - case_OFALL: + case OXFALL: case OGOTO: case OLABEL: case ORETJMP: // Special: n->left is not an expression; save as is. - *out = list(*out, n); + order->out = list(order->out, n); break; case OCALLFUNC: case OCALLINTER: case OCALLMETH: // Special: handle call arguments. - ordercall(n, out); - *out = list(*out, n); + t = marktemp(order); + ordercall(n, order); + order->out = list(order->out, n); + cleantemp(t, order); break; case ODEFER: case OPROC: // Special: order arguments to inner call but not call itself. - ordercall(n->left, out); - *out = list(*out, n); + t = marktemp(order); + switch(n->left->op) { + case ODELETE: + // Delete will take the address of the key. + // Copy key into new temp and do not clean it + // (it persists beyond the statement). + orderexprlist(n->left->list, order); + t1 = marktemp(order); + np = &n->left->list->next->n; // map key + *np = ordercopyexpr(*np, (*np)->type, order, 0); + poptemp(t1, order); + break; + default: + ordercall(n->left, order); + break; + } + order->out = list(order->out, n); + cleantemp(t, order); + break; + + case ODELETE: + t = marktemp(order); + orderexpr(&n->list->n, order); + orderexpr(&n->list->next->n, order); + orderaddrtemp(&n->list->next->n, order); // map key + order->out = list(order->out, n); + cleantemp(t, order); break; case OFOR: - orderexprinplace(&n->ntest); - orderstmtinplace(&n->nincr); + // Clean temporaries from condition evaluation at + // beginning of loop body and after for statement. + t = marktemp(order); + orderexprinplace(&n->ntest, order); + l = nil; + cleantempnopop(t, order, &l); + n->nbody = concat(l, n->nbody); orderblock(&n->nbody); - *out = list(*out, n); + orderstmtinplace(&n->nincr); + order->out = list(order->out, n); + cleantemp(t, order); break; case OIF: - orderexprinplace(&n->ntest); + // Clean temporaries from condition at + // beginning of both branches. + t = marktemp(order); + orderexprinplace(&n->ntest, order); + l = nil; + cleantempnopop(t, order, &l); + n->nbody = concat(l, n->nbody); + l = nil; + cleantempnopop(t, order, &l); + n->nelse = concat(l, n->nelse); + poptemp(t, order); orderblock(&n->nbody); orderblock(&n->nelse); - *out = list(*out, n); + order->out = list(order->out, n); + break; + + case OPANIC: + // Special: argument will be converted to interface using convT2E + // so make sure it is an addressable temporary. + t = marktemp(order); + orderexpr(&n->left, order); + if(!isinter(n->left->type)) + orderaddrtemp(&n->left, order); + order->out = list(order->out, n); + cleantemp(t, order); break; case ORANGE: - orderexpr(&n->right, out); + // n->right is the expression being ranged over. + // order it, and then make a copy if we need one. + // We almost always do, to ensure that we don't + // see any value changes made during the loop. + // Usually the copy is cheap (e.g., array pointer, chan, slice, string are all tiny). + // The exception is ranging over an array value (not a slice, not a pointer to array), + // which must make a copy to avoid seeing updates made during + // the range body. Ranging over an array value is uncommon though. + t = marktemp(order); + orderexpr(&n->right, order); + switch(n->type->etype) { + default: + fatal("orderstmt range %T", n->type); + case TARRAY: + if(count(n->list) < 2 || isblank(n->list->next->n)) { + // for i := range x will only use x once, to compute len(x). + // No need to copy it. + break; + } + // fall through + case TCHAN: + case TSTRING: + // chan, string, slice, array ranges use value multiple times. + // make copy. + r = n->right; + if(r->type->etype == TSTRING && r->type != types[TSTRING]) { + r = nod(OCONV, r, N); + r->type = types[TSTRING]; + typecheck(&r, Erv); + } + n->right = ordercopyexpr(r, r->type, order, 0); + break; + case TMAP: + // copy the map value in case it is a map literal. + // TODO(rsc): Make tmp = literal expressions reuse tmp. + // For maps tmp is just one word so it hardly matters. + r = n->right; + n->right = ordercopyexpr(r, r->type, order, 0); + // n->alloc is the temp for the iterator. + n->alloc = ordertemp(types[TUINT8], order, 1); + break; + } for(l=n->list; l; l=l->next) - orderexprinplace(&l->n); + orderexprinplace(&l->n, order); orderblock(&n->nbody); - *out = list(*out, n); + order->out = list(order->out, n); + cleantemp(t, order); break; case ORETURN: - ordercallargs(&n->list, out); - *out = list(*out, n); + ordercallargs(&n->list, order); + order->out = list(order->out, n); break; case OSELECT: + // Special: clean case temporaries in each block entry. + // Select must enter one of its blocks, so there is no + // need for a cleaning at the end. + t = marktemp(order); for(l=n->list; l; l=l->next) { if(l->n->op != OXCASE) fatal("order select case %O", l->n->op); r = l->n->left; - if(r == nil) - continue; - switch(r->op) { - case OSELRECV: - case OSELRECV2: - orderexprinplace(&r->left); - orderexprinplace(&r->ntest); - orderexpr(&r->right->left, &l->n->ninit); - break; - case OSEND: - orderexpr(&r->left, &l->n->ninit); - orderexpr(&r->right, &l->n->ninit); - break; + setlineno(l->n); + // Append any new body prologue to ninit. + // The next loop will insert ninit into nbody. + if(l->n->ninit != nil) + fatal("order select ninit"); + if(r != nil) { + switch(r->op) { + default: + yyerror("unknown op in select %O", r->op); + dump("select case", r); + break; + + case OSELRECV: + case OSELRECV2: + // If this is case x := <-ch or case x, y := <-ch, the case has + // the ODCL nodes to declare x and y. We want to delay that + // declaration (and possible allocation) until inside the case body. + // Delete the ODCL nodes here and recreate them inside the body below. + if(r->colas) { + t = r->ninit; + if(t != nil && t->n->op == ODCL && t->n->left == r->left) + t = t->next; + if(t != nil && t->n->op == ODCL && t->n->left == r->ntest) + t = t->next; + if(t == nil) + r->ninit = nil; + } + if(r->ninit != nil) { + yyerror("ninit on select recv"); + dumplist("ninit", r->ninit); + } + // case x = <-c + // case x, ok = <-c + // r->left is x, r->ntest is ok, r->right is ORECV, r->right->left is c. + // r->left == N means 'case <-c'. + // c is always evaluated; x and ok are only evaluated when assigned. + orderexpr(&r->right->left, order); + + // Introduce temporary for receive and move actual copy into case body. + // avoids problems with target being addressed, as usual. + // NOTE: If we wanted to be clever, we could arrange for just one + // temporary per distinct type, sharing the temp among all receives + // with that temp. Similarly one ok bool could be shared among all + // the x,ok receives. Not worth doing until there's a clear need. + if(r->left != N && isblank(r->left)) + r->left = N; + if(r->left != N) { + // use channel element type for temporary to avoid conversions, + // such as in case interfacevalue = <-intchan. + // the conversion happens in the OAS instead. + tmp1 = r->left; + if(r->colas) { + tmp2 = nod(ODCL, tmp1, N); + typecheck(&tmp2, Etop); + l->n->ninit = list(l->n->ninit, tmp2); + } + r->left = ordertemp(r->right->left->type->type, order, haspointers(r->right->left->type->type)); + tmp2 = nod(OAS, tmp1, r->left); + typecheck(&tmp2, Etop); + l->n->ninit = list(l->n->ninit, tmp2); + } + if(r->ntest != N && isblank(r->ntest)) + r->ntest = N; + if(r->ntest != N) { + tmp1 = r->ntest; + if(r->colas) { + tmp2 = nod(ODCL, tmp1, N); + typecheck(&tmp2, Etop); + l->n->ninit = list(l->n->ninit, tmp2); + } + r->ntest = ordertemp(tmp1->type, order, 0); + tmp2 = nod(OAS, tmp1, r->ntest); + typecheck(&tmp2, Etop); + l->n->ninit = list(l->n->ninit, tmp2); + } + orderblock(&l->n->ninit); + break; + + case OSEND: + if(r->ninit != nil) { + yyerror("ninit on select send"); + dumplist("ninit", r->ninit); + } + // case c <- x + // r->left is c, r->right is x, both are always evaluated. + orderexpr(&r->left, order); + if(!istemp(r->left)) + r->left = ordercopyexpr(r->left, r->left->type, order, 0); + orderexpr(&r->right, order); + if(!istemp(r->right)) + r->right = ordercopyexpr(r->right, r->right->type, order, 0); + break; + } } + orderblock(&l->n->nbody); } - *out = list(*out, n); + // Now that we have accumulated all the temporaries, clean them. + // Also insert any ninit queued during the previous loop. + // (The temporary cleaning must follow that ninit work.) + for(l=n->list; l; l=l->next) { + cleantempnopop(t, order, &l->n->ninit); + l->n->nbody = concat(l->n->ninit, l->n->nbody); + l->n->ninit = nil; + } + order->out = list(order->out, n); + poptemp(t, order); + break; + + case OSEND: + // Special: value being sent is passed as a pointer; make it addressable. + t = marktemp(order); + orderexpr(&n->left, order); + orderexpr(&n->right, order); + orderaddrtemp(&n->right, order); + order->out = list(order->out, n); + cleantemp(t, order); break; case OSWITCH: - orderexpr(&n->ntest, out); + // TODO(rsc): Clean temporaries more aggressively. + // Note that because walkswitch will rewrite some of the + // switch into a binary search, this is not as easy as it looks. + // (If we ran that code here we could invoke orderstmt on + // the if-else chain instead.) + // For now just clean all the temporaries at the end. + // In practice that's fine. + t = marktemp(order); + orderexpr(&n->ntest, order); for(l=n->list; l; l=l->next) { if(l->n->op != OXCASE) fatal("order switch case %O", l->n->op); - orderexpr(&l->n->left, &l->n->ninit); + orderexprlistinplace(l->n->list, order); + orderblock(&l->n->nbody); } - *out = list(*out, n); + order->out = list(order->out, n); + cleantemp(t, order); break; - - case OXFALL: - yyerror("fallthrough statement out of place"); - n->op = OFALL; - goto case_OFALL; } lineno = lno; } +// Orderexprlist orders the expression list l into order. +static void +orderexprlist(NodeList *l, Order *order) +{ + for(; l; l=l->next) + orderexpr(&l->n, order); +} + +// Orderexprlist orders the expression list l but saves +// the side effects on the individual expression ninit lists. static void -orderexprlist(NodeList *l, NodeList **out) +orderexprlistinplace(NodeList *l, Order *order) { for(; l; l=l->next) - orderexpr(&l->n, out); + orderexprinplace(&l->n, order); } +// Orderexpr orders a single expression, appending side +// effects to order->out as needed. static void -orderexpr(Node **np, NodeList **out) +orderexpr(Node **np, Order *order) { Node *n; + NodeList *mark, *l; + Type *t; int lno; n = *np; @@ -325,31 +947,113 @@ orderexpr(Node **np, NodeList **out) return; lno = setlineno(n); - orderinit(n, out); + orderinit(n, order); switch(n->op) { default: - orderexpr(&n->left, out); - orderexpr(&n->right, out); - orderexprlist(n->list, out); - orderexprlist(n->rlist, out); + orderexpr(&n->left, order); + orderexpr(&n->right, order); + orderexprlist(n->list, order); + orderexprlist(n->rlist, order); + break; + + case OADDSTR: + // Addition of strings turns into a function call. + // Allocate a temporary to hold the strings. + // Fewer than 5 strings use direct runtime helpers. + orderexprlist(n->list, order); + if(count(n->list) > 5) { + t = typ(TARRAY); + t->bound = count(n->list); + t->type = types[TSTRING]; + n->alloc = ordertemp(t, order, 0); + } + break; + + case OINDEXMAP: + // key must be addressable + orderexpr(&n->left, order); + orderexpr(&n->right, order); + + // For x = m[string(k)] where k is []byte, the allocation of + // backing bytes for the string can be avoided by reusing + // the []byte backing array. This is a special case that it + // would be nice to handle more generally, but because + // there are no []byte-keyed maps, this specific case comes + // up in important cases in practice. See issue 3512. + // Nothing can change the []byte we are not copying before + // the map index, because the map access is going to + // be forced to happen immediately following this + // conversion (by the ordercopyexpr a few lines below). + if(n->etype == 0 && n->right->op == OARRAYBYTESTR) + n->right->op = OARRAYBYTESTRTMP; + + orderaddrtemp(&n->right, order); + if(n->etype == 0) { + // use of value (not being assigned); + // make copy in temporary. + n = ordercopyexpr(n, n->type, order, 0); + } + break; + + case OCONVIFACE: + // concrete type (not interface) argument must be addressable + // temporary to pass to runtime. + orderexpr(&n->left, order); + if(!isinter(n->left->type)) + orderaddrtemp(&n->left, order); break; case OANDAND: case OOROR: - orderexpr(&n->left, out); - orderexprinplace(&n->right); + mark = marktemp(order); + orderexpr(&n->left, order); + // Clean temporaries from first branch at beginning of second. + // Leave them on the stack so that they can be killed in the outer + // context in case the short circuit is taken. + l = nil; + cleantempnopop(mark, order, &l); + n->right->ninit = concat(l, n->right->ninit); + orderexprinplace(&n->right, order); break; case OCALLFUNC: case OCALLMETH: case OCALLINTER: - ordercall(n, out); - n = copyexpr(n, n->type, out); + case OAPPEND: + case OCOMPLEX: + ordercall(n, order); + n = ordercopyexpr(n, n->type, order, 0); + break; + + case OCLOSURE: + if(n->noescape && n->cvars != nil) + n->alloc = ordertemp(types[TUINT8], order, 0); // walk will fill in correct type + break; + + case OARRAYLIT: + case OCALLPART: + orderexpr(&n->left, order); + orderexpr(&n->right, order); + orderexprlist(n->list, order); + orderexprlist(n->rlist, order); + if(n->noescape) + n->alloc = ordertemp(types[TUINT8], order, 0); // walk will fill in correct type + break; + + case ODDDARG: + if(n->noescape) { + // The ddd argument does not live beyond the call it is created for. + // Allocate a temporary that will be cleaned up when this statement + // completes. We could be more aggressive and try to arrange for it + // to be cleaned up when the call completes. + n->alloc = ordertemp(n->type->type, order, 0); + } break; case ORECV: - n = copyexpr(n, n->type, out); + orderexpr(&n->left, order); + n = ordercopyexpr(n, n->type, order, 1); break; } diff --git a/src/cmd/gc/pgen.c b/src/cmd/gc/pgen.c index 2850af6bb..40620c3da 100644 --- a/src/cmd/gc/pgen.c +++ b/src/cmd/gc/pgen.c @@ -8,30 +8,159 @@ #include #include +#include "md5.h" #include "gg.h" #include "opt.h" #include "../../pkg/runtime/funcdata.h" -enum { BitsPerPointer = 2 }; - static void allocauto(Prog* p); -static void dumpgcargs(Node*, Sym*); -static Bvec* dumpgclocals(Node*, Sym*); + +static Sym* +makefuncdatasym(char *namefmt, int64 funcdatakind) +{ + Node nod; + Node *pnod; + Sym *sym; + static int32 nsym; + + snprint(namebuf, sizeof(namebuf), namefmt, nsym++); + sym = lookup(namebuf); + pnod = newname(sym); + pnod->class = PEXTERN; + nodconst(&nod, types[TINT32], funcdatakind); + gins(AFUNCDATA, &nod, pnod); + return sym; +} + +// gvardef inserts a VARDEF for n into the instruction stream. +// VARDEF is an annotation for the liveness analysis, marking a place +// where a complete initialization (definition) of a variable begins. +// Since the liveness analysis can see initialization of single-word +// variables quite easy, gvardef is usually only called for multi-word +// or 'fat' variables, those satisfying isfat(n->type). +// However, gvardef is also called when a non-fat variable is initialized +// via a block move; the only time this happens is when you have +// return f() +// for a function with multiple return values exactly matching the return +// types of the current function. +// +// A 'VARDEF x' annotation in the instruction stream tells the liveness +// analysis to behave as though the variable x is being initialized at that +// point in the instruction stream. The VARDEF must appear before the +// actual (multi-instruction) initialization, and it must also appear after +// any uses of the previous value, if any. For example, if compiling: +// +// x = x[1:] +// +// it is important to generate code like: +// +// base, len, cap = pieces of x[1:] +// VARDEF x +// x = {base, len, cap} +// +// If instead the generated code looked like: +// +// VARDEF x +// base, len, cap = pieces of x[1:] +// x = {base, len, cap} +// +// then the liveness analysis would decide the previous value of x was +// unnecessary even though it is about to be used by the x[1:] computation. +// Similarly, if the generated code looked like: +// +// base, len, cap = pieces of x[1:] +// x = {base, len, cap} +// VARDEF x +// +// then the liveness analysis will not preserve the new value of x, because +// the VARDEF appears to have "overwritten" it. +// +// VARDEF is a bit of a kludge to work around the fact that the instruction +// stream is working on single-word values but the liveness analysis +// wants to work on individual variables, which might be multi-word +// aggregates. It might make sense at some point to look into letting +// the liveness analysis work on single-word values as well, although +// there are complications around interface values, slices, and strings, +// all of which cannot be treated as individual words. +// +// VARKILL is the opposite of VARDEF: it marks a value as no longer needed, +// even if its address has been taken. That is, a VARKILL annotation asserts +// that its argument is certainly dead, for use when the liveness analysis +// would not otherwise be able to deduce that fact. + +static void +gvardefx(Node *n, int as) +{ + if(n == N) + fatal("gvardef nil"); + if(n->op != ONAME) { + yyerror("gvardef %#O; %N", n->op, n); + return; + } + switch(n->class) { + case PAUTO: + case PPARAM: + case PPARAMOUT: + gins(as, N, n); + } +} + +void +gvardef(Node *n) +{ + gvardefx(n, AVARDEF); +} + +void +gvarkill(Node *n) +{ + gvardefx(n, AVARKILL); +} + +static void +removevardef(Prog *firstp) +{ + Prog *p; + + for(p = firstp; p != P; p = p->link) { + while(p->link != P && (p->link->as == AVARDEF || p->link->as == AVARKILL)) + p->link = p->link->link; + if(p->to.type == D_BRANCH) + while(p->to.u.branch != P && (p->to.u.branch->as == AVARDEF || p->to.u.branch->as == AVARKILL)) + p->to.u.branch = p->to.u.branch->link; + } +} + +static void +gcsymdup(Sym *s) +{ + LSym *ls; + uint64 lo, hi; + + ls = linksym(s); + if(ls->nr > 0) + fatal("cannot rosymdup %s with relocations", ls->name); + MD5 d; + md5reset(&d); + md5write(&d, ls->p, ls->np); + lo = md5sum(&d, &hi); + ls->name = smprint("gclocals·%016llux%016llux", lo, hi); + ls->dupok = 1; +} void compile(Node *fn) { - Bvec *bv; Plist *pl; - Node nod1, *n, *gcargsnod, *gclocalsnod; - Prog *ptxt, *p, *p1; + Node nod1, *n; + Prog *ptxt, *p; int32 lno; Type *t; Iter save; vlong oldstksize; NodeList *l; - Sym *gcargssym, *gclocalssym; - static int ngcargs, ngclocals; + Sym *gcargs; + Sym *gclocals; if(newproc == N) { newproc = sysfunc("newproc"); @@ -45,7 +174,7 @@ compile(Node *fn) lno = setlineno(fn); if(fn->nbody == nil) { - if(pure_go || memcmp(fn->nname->sym->name, "init·", 6) == 0) + if(pure_go || strncmp(fn->nname->sym->name, "init·", 6) == 0) yyerror("missing function body", fn); goto ret; } @@ -88,7 +217,7 @@ compile(Node *fn) breakpc = P; pl = newplist(); - pl->name = curfn->nname; + pl->name = linksym(curfn->nname->sym); setlineno(curfn); @@ -98,6 +227,8 @@ compile(Node *fn) ptxt->TEXTFLAG |= DUPOK; if(fn->wrapper) ptxt->TEXTFLAG |= WRAPPER; + if(fn->needctxt) + ptxt->TEXTFLAG |= NEEDCTXT; // Clumsy but important. // See test/recover.go for test cases and src/pkg/reflect/value.go @@ -111,21 +242,8 @@ compile(Node *fn) ginit(); - snprint(namebuf, sizeof namebuf, "gcargs·%d", ngcargs++); - gcargssym = lookup(namebuf); - gcargsnod = newname(gcargssym); - gcargsnod->class = PEXTERN; - - nodconst(&nod1, types[TINT32], FUNCDATA_GCArgs); - gins(AFUNCDATA, &nod1, gcargsnod); - - snprint(namebuf, sizeof(namebuf), "gclocals·%d", ngclocals++); - gclocalssym = lookup(namebuf); - gclocalsnod = newname(gclocalssym); - gclocalsnod->class = PEXTERN; - - nodconst(&nod1, types[TINT32], FUNCDATA_GCLocals); - gins(AFUNCDATA, &nod1, gclocalsnod); + gcargs = makefuncdatasym("gcargs·%d", FUNCDATA_ArgsPointerMaps); + gclocals = makefuncdatasym("gclocals·%d", FUNCDATA_LocalsPointerMaps); for(t=curfn->paramfld; t; t=t->down) gtrack(tracksym(t->type)); @@ -140,20 +258,12 @@ compile(Node *fn) case PPARAMOUT: nodconst(&nod1, types[TUINTPTR], l->n->type->width); p = gins(ATYPE, l->n, &nod1); - p->from.gotype = ngotype(l->n); + p->from.gotype = linksym(ngotype(l->n)); break; } } genlist(curfn->enter); - - retpc = nil; - if(hasdefer || curfn->exit) { - p1 = gjmp(nil); - retpc = gjmp(nil); - patch(p1, pc); - } - genlist(curfn->nbody); gclean(); checklabels(); @@ -165,13 +275,15 @@ compile(Node *fn) if(curfn->type->outtuple != 0) ginscall(throwreturn, 0); - if(retpc) - patch(retpc, pc); ginit(); - if(hasdefer) - ginscall(deferreturn, 0); - if(curfn->exit) - genlist(curfn->exit); + // TODO: Determine when the final cgen_ret can be omitted. Perhaps always? + cgen_ret(nil); + if(hasdefer) { + // deferreturn pretends to have one uintptr argument. + // Reserve space for it so stack scanner is happy. + if(maxarg < widthptr) + maxarg = widthptr; + } gclean(); if(nerrors != 0) goto ret; @@ -179,6 +291,7 @@ compile(Node *fn) pc->as = ARET; // overwrite AEND pc->lineno = lineno; + fixjmp(ptxt); if(!debug['N'] || debug['R'] || debug['P']) { regopt(ptxt); nilopt(ptxt); @@ -190,6 +303,7 @@ compile(Node *fn) if(0) print("allocauto: %lld to %lld\n", oldstksize, (vlong)stksize); + USED(oldstksize); setlineno(curfn); if((int64)stksize+maxarg > (1ULL<<31)) { @@ -198,184 +312,21 @@ compile(Node *fn) } // Emit garbage collection symbols. - dumpgcargs(fn, gcargssym); - bv = dumpgclocals(curfn, gclocalssym); + liveness(curfn, ptxt, gcargs, gclocals); + gcsymdup(gcargs); + gcsymdup(gclocals); - defframe(ptxt, bv); - free(bv); + defframe(ptxt); if(0) frame(0); + // Remove leftover instrumentation from the instruction stream. + removevardef(ptxt); ret: lineno = lno; } -static void -walktype1(Type *t, vlong *xoffset, Bvec *bv) -{ - vlong fieldoffset, i, o; - Type *t1; - - if(t->align > 0 && (*xoffset % t->align) != 0) - fatal("walktype1: invalid initial alignment, %T", t); - - switch(t->etype) { - case TINT8: - case TUINT8: - case TINT16: - case TUINT16: - case TINT32: - case TUINT32: - case TINT64: - case TUINT64: - case TINT: - case TUINT: - case TUINTPTR: - case TBOOL: - case TFLOAT32: - case TFLOAT64: - case TCOMPLEX64: - case TCOMPLEX128: - *xoffset += t->width; - break; - - case TPTR32: - case TPTR64: - case TUNSAFEPTR: - case TFUNC: - case TCHAN: - case TMAP: - if(*xoffset % widthptr != 0) - fatal("walktype1: invalid alignment, %T", t); - bvset(bv, (*xoffset / widthptr) * BitsPerPointer); - *xoffset += t->width; - break; - - case TSTRING: - // struct { byte *str; intgo len; } - if(*xoffset % widthptr != 0) - fatal("walktype1: invalid alignment, %T", t); - bvset(bv, (*xoffset / widthptr) * BitsPerPointer); - *xoffset += t->width; - break; - - case TINTER: - // struct { Itab* tab; union { void* ptr, uintptr val } data; } - // or, when isnilinter(t)==true: - // struct { Type* type; union { void* ptr, uintptr val } data; } - if(*xoffset % widthptr != 0) - fatal("walktype1: invalid alignment, %T", t); - bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 1); - if(isnilinter(t)) - bvset(bv, ((*xoffset / widthptr) * BitsPerPointer)); - *xoffset += t->width; - break; - - case TARRAY: - // The value of t->bound is -1 for slices types and >0 for - // for fixed array types. All other values are invalid. - if(t->bound < -1) - fatal("walktype1: invalid bound, %T", t); - if(isslice(t)) { - // struct { byte* array; uintgo len; uintgo cap; } - if(*xoffset % widthptr != 0) - fatal("walktype1: invalid TARRAY alignment, %T", t); - bvset(bv, (*xoffset / widthptr) * BitsPerPointer); - *xoffset += t->width; - } else if(!haspointers(t->type)) - *xoffset += t->width; - else - for(i = 0; i < t->bound; ++i) - walktype1(t->type, xoffset, bv); - break; - - case TSTRUCT: - o = 0; - for(t1 = t->type; t1 != T; t1 = t1->down) { - fieldoffset = t1->width; - *xoffset += fieldoffset - o; - walktype1(t1->type, xoffset, bv); - o = fieldoffset + t1->type->width; - } - *xoffset += t->width - o; - break; - - default: - fatal("walktype1: unexpected type, %T", t); - } -} - -static void -walktype(Type *type, Bvec *bv) -{ - vlong xoffset; - - // Start the walk at offset 0. The correct offset will be - // filled in by the first type encountered during the walk. - xoffset = 0; - walktype1(type, &xoffset, bv); -} - -// Compute a bit vector to describe the pointer-containing locations -// in the in and out argument list and dump the bitvector length and -// data to the provided symbol. -static void -dumpgcargs(Node *fn, Sym *sym) -{ - Type *thistype, *inargtype, *outargtype; - Bvec *bv; - int32 i; - int off; - - thistype = getthisx(fn->type); - inargtype = getinargx(fn->type); - outargtype = getoutargx(fn->type); - bv = bvalloc((fn->type->argwid / widthptr) * BitsPerPointer); - if(thistype != nil) - walktype(thistype, bv); - if(inargtype != nil) - walktype(inargtype, bv); - if(outargtype != nil) - walktype(outargtype, bv); - off = duint32(sym, 0, bv->n); - for(i = 0; i < bv->n; i += 32) - off = duint32(sym, off, bv->b[i/32]); - free(bv); - ggloblsym(sym, off, 0, 1); -} - -// Compute a bit vector to describe the pointer-containing locations -// in local variables and dump the bitvector length and data out to -// the provided symbol. Return the vector for use and freeing by caller. -static Bvec* -dumpgclocals(Node* fn, Sym *sym) -{ - Bvec *bv; - NodeList *ll; - Node *node; - vlong xoffset; - int32 i; - int off; - - bv = bvalloc((stkptrsize / widthptr) * BitsPerPointer); - for(ll = fn->dcl; ll != nil; ll = ll->next) { - node = ll->n; - if(node->class == PAUTO && node->op == ONAME) { - if(haspointers(node->type)) { - xoffset = node->xoffset + stkptrsize; - walktype1(node->type, &xoffset, bv); - } - } - } - off = duint32(sym, 0, bv->n); - for(i = 0; i < bv->n; i += 32) { - off = duint32(sym, off, bv->b[i/32]); - } - ggloblsym(sym, off, 0, 1); - return bv; -} - // Sort the list of stack variables. Autos after anything else, // within autos, unused after used, within used, things with // pointers first, zeroed things first, and then decreasing size. @@ -415,7 +366,8 @@ cmpstackvar(Node *a, Node *b) return +1; if(a->type->width > b->type->width) return -1; - return 0; + + return strcmp(a->sym->name, b->sym->name); } // TODO(lvd) find out where the PAUTO/OLITERAL nodes come from. @@ -428,7 +380,6 @@ allocauto(Prog* ptxt) stksize = 0; stkptrsize = 0; - stkzerosize = 0; if(curfn->dcl == nil) return; @@ -440,13 +391,6 @@ allocauto(Prog* ptxt) markautoused(ptxt); - if(precisestack_enabled) { - // TODO: Remove when liveness analysis sets needzero instead. - for(ll=curfn->dcl; ll != nil; ll=ll->next) - if(ll->n->class == PAUTO) - ll->n->needzero = 1; // ll->n->addrtaken; - } - listsort(&curfn->dcl, cmpstackvar); // Unused autos are at the end, chop 'em off. @@ -480,11 +424,8 @@ allocauto(Prog* ptxt) fatal("bad width"); stksize += w; stksize = rnd(stksize, n->type->align); - if(haspointers(n->type)) { + if(haspointers(n->type)) stkptrsize = stksize; - if(n->needzero) - stkzerosize = stksize; - } if(thechar == '5') stksize = rnd(stksize, widthptr); if(stksize >= (1ULL<<31)) { @@ -493,9 +434,8 @@ allocauto(Prog* ptxt) } n->stkdelta = -stksize - n->xoffset; } - stksize = rnd(stksize, widthptr); - stkptrsize = rnd(stkptrsize, widthptr); - stkzerosize = rnd(stkzerosize, widthptr); + stksize = rnd(stksize, widthreg); + stkptrsize = rnd(stkptrsize, widthreg); fixautoused(ptxt); @@ -538,12 +478,12 @@ cgen_checknil(Node *n) if(disable_checknil) return; - // Ideally we wouldn't see any TUINTPTR here, but we do. - if(n->type == T || (!isptr[n->type->etype] && n->type->etype != TUINTPTR && n->type->etype != TUNSAFEPTR)) { + // Ideally we wouldn't see any integer types here, but we do. + if(n->type == T || (!isptr[n->type->etype] && !isint[n->type->etype] && n->type->etype != TUNSAFEPTR)) { dump("checknil", n); fatal("bad checknil"); } - if((thechar == '5' && n->op != OREGISTER) || !n->addable) { + if((thechar == '5' && n->op != OREGISTER) || !n->addable || n->op == OLITERAL) { regalloc(®, types[tptr], n); cgen(n, ®); gins(ACHECKNIL, ®, N); diff --git a/src/cmd/gc/plive.c b/src/cmd/gc/plive.c new file mode 100644 index 000000000..eb8901733 --- /dev/null +++ b/src/cmd/gc/plive.c @@ -0,0 +1,1985 @@ +// Copyright 2013 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. + +// Garbage collector liveness bitmap generation. + +// The command line flag -live causes this code to print debug information. +// The levels are: +// +// -live (aka -live=1): print liveness lists as code warnings at safe points +// -live=2: print an assembly listing with liveness annotations +// -live=3: print information during each computation phase (much chattier) +// +// Each level includes the earlier output as well. + +#include +#include +#include "gg.h" +#include "opt.h" +#include "../../pkg/runtime/funcdata.h" + +enum { BitsPerPointer = 2 }; + +enum { + UNVISITED = 0, + VISITED = 1, +}; + +// An ordinary basic block. +// +// Instructions are threaded together in a doubly-linked list. To iterate in +// program order follow the link pointer from the first node and stop after the +// last node has been visited +// +// for(p = bb->first;; p = p->link) { +// ... +// if(p == bb->last) +// break; +// } +// +// To iterate in reverse program order by following the opt pointer from the +// last node +// +// for(p = bb->last; p != nil; p = p->opt) { +// ... +// } +typedef struct BasicBlock BasicBlock; +struct BasicBlock { + // An array of preceding blocks. If the length of this array is 0 the + // block is probably the start block of the CFG. + Array *pred; + + // An array out succeeding blocks. If the length of this array is zero, + // the block probably ends in a return instruction. + Array *succ; + + // First instruction in the block. When part of a fully initialized + // control flow graph, the opt member will be nil. + Prog *first; + + // Last instruction in the basic block. + Prog *last; + + // The reverse post order number. This value is initialized to -1 and + // will be replaced by a non-negative value when the CFG is constructed. + // After CFG construction, if rpo is -1 this block is unreachable. + int rpo; + + // State to denote whether the block has been visited during a + // traversal. + int mark; + + // For use during livenessepilogue. + int lastbitmapindex; +}; + +// A collection of global state used by liveness analysis. +typedef struct Liveness Liveness; +struct Liveness { + // A pointer to the node corresponding to the function being analyzed. + Node *fn; + + // A linked list of instructions for this function. + Prog *ptxt; + + // A list of arguments and local variables in this function. + Array *vars; + + // A list of basic blocks that are overlayed on the instruction list. + // The blocks are roughly in the same order as the instructions + // in the function (first block has TEXT instruction, and so on). + Array *cfg; + + // Summary sets of block effects. + // The Bvec** is indexed by bb->rpo to yield a single Bvec*. + // That bit vector is indexed by variable number (same as lv->vars). + // + // Computed during livenessprologue using only the content of + // individual blocks: + // + // uevar: upward exposed variables (used before set in block) + // varkill: killed variables (set in block) + // avarinit: addrtaken variables set or used (proof of initialization) + // + // Computed during livenesssolve using control flow information: + // + // livein: variables live at block entry + // liveout: variables live at block exit + // avarinitany: addrtaken variables possibly initialized at block exit + // (initialized in block or at exit from any predecessor block) + // avarinitall: addrtaken variables certainly initialized at block exit + // (initialized in block or at exit from all predecessor blocks) + Bvec **uevar; + Bvec **varkill; + Bvec **livein; + Bvec **liveout; + Bvec **avarinit; + Bvec **avarinitany; + Bvec **avarinitall; + + // An array with a bit vector for each safe point tracking live pointers + // in the arguments and locals area, indexed by bb->rpo. + Array *argslivepointers; + Array *livepointers; +}; + +static void* +xmalloc(uintptr size) +{ + void *result; + + result = malloc(size); + if(result == nil) + fatal("malloc failed"); + return result; +} + +// Constructs a new basic block containing a single instruction. +static BasicBlock* +newblock(Prog *prog) +{ + BasicBlock *result; + + if(prog == nil) + fatal("newblock: prog cannot be nil"); + result = xmalloc(sizeof(*result)); + result->rpo = -1; + result->mark = UNVISITED; + result->first = prog; + result->last = prog; + result->pred = arraynew(2, sizeof(BasicBlock*)); + result->succ = arraynew(2, sizeof(BasicBlock*)); + return result; +} + +// Frees a basic block and all of its leaf data structures. +static void +freeblock(BasicBlock *bb) +{ + if(bb == nil) + fatal("freeblock: cannot free nil"); + arrayfree(bb->pred); + arrayfree(bb->succ); + free(bb); +} + +// Adds an edge between two basic blocks by making from a predecessor of to and +// to a successor of from. +static void +addedge(BasicBlock *from, BasicBlock *to) +{ + if(from == nil) + fatal("addedge: from is nil"); + if(to == nil) + fatal("addedge: to is nil"); + arrayadd(from->succ, &to); + arrayadd(to->pred, &from); +} + +// Inserts prev before curr in the instruction +// stream. Any control flow, such as branches or fall throughs, that target the +// existing instruction are adjusted to target the new instruction. +static void +splicebefore(Liveness *lv, BasicBlock *bb, Prog *prev, Prog *curr) +{ + Prog *next, tmp; + + USED(lv); + + // There may be other instructions pointing at curr, + // and we want them to now point at prev. Instead of + // trying to find all such instructions, swap the contents + // so that the problem becomes inserting next after curr. + // The "opt" field is the backward link in the linked list. + + // Overwrite curr's data with prev, but keep the list links. + tmp = *curr; + *curr = *prev; + curr->opt = tmp.opt; + curr->link = tmp.link; + + // Overwrite prev (now next) with curr's old data. + next = prev; + *next = tmp; + next->opt = nil; + next->link = nil; + + // Now insert next after curr. + next->link = curr->link; + next->opt = curr; + curr->link = next; + if(next->link && next->link->opt == curr) + next->link->opt = next; + + if(bb->last == curr) + bb->last = next; +} + +// A pretty printer for basic blocks. +static void +printblock(BasicBlock *bb) +{ + BasicBlock *pred; + BasicBlock *succ; + Prog *prog; + int i; + + print("basic block %d\n", bb->rpo); + print("\tpred:"); + for(i = 0; i < arraylength(bb->pred); i++) { + pred = *(BasicBlock**)arrayget(bb->pred, i); + print(" %d", pred->rpo); + } + print("\n"); + print("\tsucc:"); + for(i = 0; i < arraylength(bb->succ); i++) { + succ = *(BasicBlock**)arrayget(bb->succ, i); + print(" %d", succ->rpo); + } + print("\n"); + print("\tprog:\n"); + for(prog = bb->first;; prog=prog->link) { + print("\t\t%P\n", prog); + if(prog == bb->last) + break; + } +} + + +// Iterates over a basic block applying a callback to each instruction. There +// are two criteria for termination. If the end of basic block is reached a +// value of zero is returned. If the callback returns a non-zero value, the +// iteration is stopped and the value of the callback is returned. +static int +blockany(BasicBlock *bb, int (*callback)(Prog*)) +{ + Prog *p; + int result; + + for(p = bb->last; p != nil; p = p->opt) { + result = (*callback)(p); + if(result != 0) + return result; + } + return 0; +} + +// Collects and returns and array of Node*s for functions arguments and local +// variables. +static Array* +getvariables(Node *fn) +{ + Array *result; + NodeList *ll; + + result = arraynew(0, sizeof(Node*)); + for(ll = fn->dcl; ll != nil; ll = ll->next) { + if(ll->n->op == ONAME) { + // In order for GODEBUG=gcdead=1 to work, each bitmap needs + // to contain information about all variables covered by the bitmap. + // For local variables, the bitmap only covers the stkptrsize + // bytes in the frame where variables containing pointers live. + // For arguments and results, the bitmap covers all variables, + // so we must include all the variables, even the ones without + // pointers. + switch(ll->n->class) { + case PAUTO: + if(haspointers(ll->n->type)) + arrayadd(result, &ll->n); + break; + case PPARAM: + case PPARAMOUT: + arrayadd(result, &ll->n); + break; + } + } + } + return result; +} + +// A pretty printer for control flow graphs. Takes an array of BasicBlock*s. +static void +printcfg(Array *cfg) +{ + BasicBlock *bb; + int32 i; + + for(i = 0; i < arraylength(cfg); i++) { + bb = *(BasicBlock**)arrayget(cfg, i); + printblock(bb); + } +} + +// Assigns a reverse post order number to each connected basic block using the +// standard algorithm. Unconnected blocks will not be affected. +static void +reversepostorder(BasicBlock *root, int32 *rpo) +{ + BasicBlock *bb; + int i; + + root->mark = VISITED; + for(i = 0; i < arraylength(root->succ); i++) { + bb = *(BasicBlock**)arrayget(root->succ, i); + if(bb->mark == UNVISITED) + reversepostorder(bb, rpo); + } + *rpo -= 1; + root->rpo = *rpo; +} + +// Comparison predicate used for sorting basic blocks by their rpo in ascending +// order. +static int +blockrpocmp(const void *p1, const void *p2) +{ + BasicBlock *bb1; + BasicBlock *bb2; + + bb1 = *(BasicBlock**)p1; + bb2 = *(BasicBlock**)p2; + if(bb1->rpo < bb2->rpo) + return -1; + if(bb1->rpo > bb2->rpo) + return 1; + return 0; +} + +// A pattern matcher for call instructions. Returns true when the instruction +// is a call to a specific package qualified function name. +static int +iscall(Prog *prog, LSym *name) +{ + if(prog == nil) + fatal("iscall: prog is nil"); + if(name == nil) + fatal("iscall: function name is nil"); + if(prog->as != ACALL) + return 0; + return name == prog->to.sym; +} + +// Returns true for instructions that call a runtime function implementing a +// select communication clause. +static int +isselectcommcasecall(Prog *prog) +{ + static LSym* names[5]; + int32 i; + + if(names[0] == nil) { + names[0] = linksym(pkglookup("selectsend", runtimepkg)); + names[1] = linksym(pkglookup("selectrecv", runtimepkg)); + names[2] = linksym(pkglookup("selectrecv2", runtimepkg)); + names[3] = linksym(pkglookup("selectdefault", runtimepkg)); + } + for(i = 0; names[i] != nil; i++) + if(iscall(prog, names[i])) + return 1; + return 0; +} + +// Returns true for call instructions that target runtime·newselect. +static int +isnewselect(Prog *prog) +{ + static LSym *sym; + + if(sym == nil) + sym = linksym(pkglookup("newselect", runtimepkg)); + return iscall(prog, sym); +} + +// Returns true for call instructions that target runtime·selectgo. +static int +isselectgocall(Prog *prog) +{ + static LSym *sym; + + if(sym == nil) + sym = linksym(pkglookup("selectgo", runtimepkg)); + return iscall(prog, sym); +} + +static int +isdeferreturn(Prog *prog) +{ + static LSym *sym; + + if(sym == nil) + sym = linksym(pkglookup("deferreturn", runtimepkg)); + return iscall(prog, sym); +} + +// Walk backwards from a runtime·selectgo call up to its immediately dominating +// runtime·newselect call. Any successor nodes of communication clause nodes +// are implicit successors of the runtime·selectgo call node. The goal of this +// analysis is to add these missing edges to complete the control flow graph. +static void +addselectgosucc(BasicBlock *selectgo) +{ + BasicBlock *pred; + BasicBlock *succ; + + pred = selectgo; + for(;;) { + if(arraylength(pred->pred) == 0) + fatal("selectgo does not have a newselect"); + pred = *(BasicBlock**)arrayget(pred->pred, 0); + if(blockany(pred, isselectcommcasecall)) { + // A select comm case block should have exactly one + // successor. + if(arraylength(pred->succ) != 1) + fatal("select comm case has too many successors"); + succ = *(BasicBlock**)arrayget(pred->succ, 0); + // Its successor should have exactly two successors. + // The drop through should flow to the selectgo block + // and the branch should lead to the select case + // statements block. + if(arraylength(succ->succ) != 2) + fatal("select comm case successor has too many successors"); + // Add the block as a successor of the selectgo block. + addedge(selectgo, succ); + } + if(blockany(pred, isnewselect)) { + // Reached the matching newselect. + break; + } + } +} + +// The entry point for the missing selectgo control flow algorithm. Takes an +// array of BasicBlock*s containing selectgo calls. +static void +fixselectgo(Array *selectgo) +{ + BasicBlock *bb; + int32 i; + + for(i = 0; i < arraylength(selectgo); i++) { + bb = *(BasicBlock**)arrayget(selectgo, i); + addselectgosucc(bb); + } +} + +// Constructs a control flow graph from a sequence of instructions. This +// procedure is complicated by various sources of implicit control flow that are +// not accounted for using the standard cfg construction algorithm. Returns an +// array of BasicBlock*s in control flow graph form (basic blocks ordered by +// their RPO number). +static Array* +newcfg(Prog *firstp) +{ + Prog *p; + Prog *prev; + BasicBlock *bb; + Array *cfg; + Array *selectgo; + int32 i; + int32 rpo; + + // Reset the opt field of each prog to nil. In the first and second + // passes, instructions that are labels temporarily use the opt field to + // point to their basic block. In the third pass, the opt field reset + // to point to the predecessor of an instruction in its basic block. + for(p = firstp; p != P; p = p->link) + p->opt = nil; + + // Allocate an array to remember where we have seen selectgo calls. + // These blocks will be revisited to add successor control flow edges. + selectgo = arraynew(0, sizeof(BasicBlock*)); + + // Loop through all instructions identifying branch targets + // and fall-throughs and allocate basic blocks. + cfg = arraynew(0, sizeof(BasicBlock*)); + bb = newblock(firstp); + arrayadd(cfg, &bb); + for(p = firstp; p != P; p = p->link) { + if(p->to.type == D_BRANCH) { + if(p->to.u.branch == nil) + fatal("prog branch to nil"); + if(p->to.u.branch->opt == nil) { + p->to.u.branch->opt = newblock(p->to.u.branch); + arrayadd(cfg, &p->to.u.branch->opt); + } + if(p->as != AJMP && p->link != nil && p->link->opt == nil) { + p->link->opt = newblock(p->link); + arrayadd(cfg, &p->link->opt); + } + } else if(isselectcommcasecall(p) || isselectgocall(p)) { + // Accommodate implicit selectgo control flow. + if(p->link->opt == nil) { + p->link->opt = newblock(p->link); + arrayadd(cfg, &p->link->opt); + } + } + } + + // Loop through all basic blocks maximally growing the list of + // contained instructions until a label is reached. Add edges + // for branches and fall-through instructions. + for(i = 0; i < arraylength(cfg); i++) { + bb = *(BasicBlock**)arrayget(cfg, i); + for(p = bb->last; p != nil; p = p->link) { + if(p->opt != nil && p != bb->last) + break; + bb->last = p; + + // Stop before an unreachable RET, to avoid creating + // unreachable control flow nodes. + if(p->link != nil && p->link->as == ARET && p->link->mode == 1) + break; + + // Collect basic blocks with selectgo calls. + if(isselectgocall(p)) + arrayadd(selectgo, &bb); + } + if(bb->last->to.type == D_BRANCH) + addedge(bb, bb->last->to.u.branch->opt); + if(bb->last->link != nil) { + // Add a fall-through when the instruction is + // not an unconditional control transfer. + switch(bb->last->as) { + case AJMP: + case ARET: + case AUNDEF: + break; + default: + addedge(bb, bb->last->link->opt); + } + } + } + + // Add back links so the instructions in a basic block can be traversed + // backward. This is the final state of the instruction opt field. + for(i = 0; i < arraylength(cfg); i++) { + bb = *(BasicBlock**)arrayget(cfg, i); + p = bb->first; + prev = nil; + for(;;) { + p->opt = prev; + if(p == bb->last) + break; + prev = p; + p = p->link; + } + } + + // Add missing successor edges to the selectgo blocks. + if(arraylength(selectgo)) + fixselectgo(selectgo); + arrayfree(selectgo); + + // Find a depth-first order and assign a depth-first number to + // all basic blocks. + for(i = 0; i < arraylength(cfg); i++) { + bb = *(BasicBlock**)arrayget(cfg, i); + bb->mark = UNVISITED; + } + bb = *(BasicBlock**)arrayget(cfg, 0); + rpo = arraylength(cfg); + reversepostorder(bb, &rpo); + + // Sort the basic blocks by their depth first number. The + // array is now a depth-first spanning tree with the first + // node being the root. + arraysort(cfg, blockrpocmp); + bb = *(BasicBlock**)arrayget(cfg, 0); + + // Unreachable control flow nodes are indicated by a -1 in the rpo + // field. If we see these nodes something must have gone wrong in an + // upstream compilation phase. + if(bb->rpo == -1) { + print("newcfg: unreachable basic block for %P\n", bb->last); + printcfg(cfg); + fatal("newcfg: invalid control flow graph"); + } + + return cfg; +} + +// Frees a control flow graph (an array of BasicBlock*s) and all of its leaf +// data structures. +static void +freecfg(Array *cfg) +{ + BasicBlock *bb; + BasicBlock *bb0; + Prog *p; + int32 i; + int32 len; + + len = arraylength(cfg); + if(len > 0) { + bb0 = *(BasicBlock**)arrayget(cfg, 0); + for(p = bb0->first; p != P; p = p->link) { + p->opt = nil; + } + for(i = 0; i < len; i++) { + bb = *(BasicBlock**)arrayget(cfg, i); + freeblock(bb); + } + } + arrayfree(cfg); +} + +// Returns true if the node names a variable that is otherwise uninteresting to +// the liveness computation. +static int +isfunny(Node *node) +{ + char *names[] = { ".fp", ".args", nil }; + int i; + + if(node->sym != nil && node->sym->name != nil) + for(i = 0; names[i] != nil; i++) + if(strcmp(node->sym->name, names[i]) == 0) + return 1; + return 0; +} + +// Computes the effects of an instruction on a set of +// variables. The vars argument is an array of Node*s. +// +// The output vectors give bits for variables: +// uevar - used by this instruction +// varkill - killed by this instruction +// for variables without address taken, means variable was set +// for variables with address taken, means variable was marked dead +// avarinit - initialized or referred to by this instruction, +// only for variables with address taken but not escaping to heap +// +// The avarinit output serves as a signal that the data has been +// initialized, because any use of a variable must come after its +// initialization. +static void +progeffects(Prog *prog, Array *vars, Bvec *uevar, Bvec *varkill, Bvec *avarinit) +{ + ProgInfo info; + Adr *from; + Adr *to; + Node *node; + int32 i; + int32 pos; + + bvresetall(uevar); + bvresetall(varkill); + bvresetall(avarinit); + + proginfo(&info, prog); + if(prog->as == ARET) { + // Return instructions implicitly read all the arguments. For + // the sake of correctness, out arguments must be read. For the + // sake of backtrace quality, we read in arguments as well. + // + // A return instruction with a p->to is a tail return, which brings + // the stack pointer back up (if it ever went down) and then jumps + // to a new function entirely. That form of instruction must read + // all the parameters for correctness, and similarly it must not + // read the out arguments - they won't be set until the new + // function runs. + for(i = 0; i < arraylength(vars); i++) { + node = *(Node**)arrayget(vars, i); + switch(node->class & ~PHEAP) { + case PPARAM: + bvset(uevar, i); + break; + case PPARAMOUT: + // If the result had its address taken, it is being tracked + // by the avarinit code, which does not use uevar. + // If we added it to uevar too, we'd not see any kill + // and decide that the varible was live entry, which it is not. + // So only use uevar in the non-addrtaken case. + // The p->to.type == D_NONE limits the bvset to + // non-tail-call return instructions; see note above + // the for loop for details. + if(!node->addrtaken && prog->to.type == D_NONE) + bvset(uevar, i); + break; + } + } + return; + } + if(prog->as == ATEXT) { + // A text instruction marks the entry point to a function and + // the definition point of all in arguments. + for(i = 0; i < arraylength(vars); i++) { + node = *(Node**)arrayget(vars, i); + switch(node->class & ~PHEAP) { + case PPARAM: + if(node->addrtaken) + bvset(avarinit, i); + bvset(varkill, i); + break; + } + } + return; + } + if(info.flags & (LeftRead | LeftWrite | LeftAddr)) { + from = &prog->from; + if (from->node != nil && from->sym != nil) { + switch(from->node->class & ~PHEAP) { + case PAUTO: + case PPARAM: + case PPARAMOUT: + pos = arrayindexof(vars, from->node); + if(pos == -1) + goto Next; + if(from->node->addrtaken) { + bvset(avarinit, pos); + } else { + if(info.flags & (LeftRead | LeftAddr)) + bvset(uevar, pos); + if(info.flags & LeftWrite) + if(from->node != nil && !isfat(from->node->type)) + bvset(varkill, pos); + } + } + } + } +Next: + if(info.flags & (RightRead | RightWrite | RightAddr)) { + to = &prog->to; + if (to->node != nil && to->sym != nil) { + switch(to->node->class & ~PHEAP) { + case PAUTO: + case PPARAM: + case PPARAMOUT: + pos = arrayindexof(vars, to->node); + if(pos == -1) + goto Next1; + if(to->node->addrtaken) { + if(prog->as != AVARKILL) + bvset(avarinit, pos); + if(prog->as == AVARDEF || prog->as == AVARKILL) + bvset(varkill, pos); + } else { + // RightRead is a read, obviously. + // RightAddr by itself is also implicitly a read. + // + // RightAddr|RightWrite means that the address is being taken + // but only so that the instruction can write to the value. + // It is not a read. It is equivalent to RightWrite except that + // having the RightAddr bit set keeps the registerizer from + // trying to substitute a register for the memory location. + if((info.flags & RightRead) || (info.flags & (RightAddr|RightWrite)) == RightAddr) + bvset(uevar, pos); + if(info.flags & RightWrite) + if(to->node != nil && (!isfat(to->node->type) || prog->as == AVARDEF)) + bvset(varkill, pos); + } + } + } + } +Next1:; +} + +// Constructs a new liveness structure used to hold the global state of the +// liveness computation. The cfg argument is an array of BasicBlock*s and the +// vars argument is an array of Node*s. +static Liveness* +newliveness(Node *fn, Prog *ptxt, Array *cfg, Array *vars) +{ + Liveness *result; + int32 i; + int32 nblocks; + int32 nvars; + + result = xmalloc(sizeof(*result)); + result->fn = fn; + result->ptxt = ptxt; + result->cfg = cfg; + result->vars = vars; + + nblocks = arraylength(cfg); + result->uevar = xmalloc(sizeof(Bvec*) * nblocks); + result->varkill = xmalloc(sizeof(Bvec*) * nblocks); + result->livein = xmalloc(sizeof(Bvec*) * nblocks); + result->liveout = xmalloc(sizeof(Bvec*) * nblocks); + result->avarinit = xmalloc(sizeof(Bvec*) * nblocks); + result->avarinitany = xmalloc(sizeof(Bvec*) * nblocks); + result->avarinitall = xmalloc(sizeof(Bvec*) * nblocks); + + nvars = arraylength(vars); + for(i = 0; i < nblocks; i++) { + result->uevar[i] = bvalloc(nvars); + result->varkill[i] = bvalloc(nvars); + result->livein[i] = bvalloc(nvars); + result->liveout[i] = bvalloc(nvars); + result->avarinit[i] = bvalloc(nvars); + result->avarinitany[i] = bvalloc(nvars); + result->avarinitall[i] = bvalloc(nvars); + } + + result->livepointers = arraynew(0, sizeof(Bvec*)); + result->argslivepointers = arraynew(0, sizeof(Bvec*)); + return result; +} + +// Frees the liveness structure and all of its leaf data structures. +static void +freeliveness(Liveness *lv) +{ + int32 i; + + if(lv == nil) + fatal("freeliveness: cannot free nil"); + + for(i = 0; i < arraylength(lv->livepointers); i++) + free(*(Bvec**)arrayget(lv->livepointers, i)); + arrayfree(lv->livepointers); + + for(i = 0; i < arraylength(lv->argslivepointers); i++) + free(*(Bvec**)arrayget(lv->argslivepointers, i)); + arrayfree(lv->argslivepointers); + + for(i = 0; i < arraylength(lv->cfg); i++) { + free(lv->uevar[i]); + free(lv->varkill[i]); + free(lv->livein[i]); + free(lv->liveout[i]); + free(lv->avarinit[i]); + free(lv->avarinitany[i]); + free(lv->avarinitall[i]); + } + + free(lv->uevar); + free(lv->varkill); + free(lv->livein); + free(lv->liveout); + free(lv->avarinit); + free(lv->avarinitany); + free(lv->avarinitall); + + free(lv); +} + +static void +printeffects(Prog *p, Bvec *uevar, Bvec *varkill, Bvec *avarinit) +{ + print("effects of %P", p); + print("\nuevar: "); + bvprint(uevar); + print("\nvarkill: "); + bvprint(varkill); + print("\navarinit: "); + bvprint(avarinit); + print("\n"); +} + +// Pretty print a variable node. Uses Pascal like conventions for pointers and +// addresses to avoid confusing the C like conventions used in the node variable +// names. +static void +printnode(Node *node) +{ + char *p; + char *a; + + p = haspointers(node->type) ? "^" : ""; + a = node->addrtaken ? "@" : ""; + print(" %N%s%s", node, p, a); +} + +// Pretty print a list of variables. The vars argument is an array of Node*s. +static void +printvars(char *name, Bvec *bv, Array *vars) +{ + int32 i; + + print("%s:", name); + for(i = 0; i < arraylength(vars); i++) + if(bvget(bv, i)) + printnode(*(Node**)arrayget(vars, i)); + print("\n"); +} + +// Prints a basic block annotated with the information computed by liveness +// analysis. +static void +livenessprintblock(Liveness *lv, BasicBlock *bb) +{ + BasicBlock *pred; + BasicBlock *succ; + Prog *prog; + Bvec *live; + int i; + int32 pos; + + print("basic block %d\n", bb->rpo); + + print("\tpred:"); + for(i = 0; i < arraylength(bb->pred); i++) { + pred = *(BasicBlock**)arrayget(bb->pred, i); + print(" %d", pred->rpo); + } + print("\n"); + + print("\tsucc:"); + for(i = 0; i < arraylength(bb->succ); i++) { + succ = *(BasicBlock**)arrayget(bb->succ, i); + print(" %d", succ->rpo); + } + print("\n"); + + printvars("\tuevar", lv->uevar[bb->rpo], lv->vars); + printvars("\tvarkill", lv->varkill[bb->rpo], lv->vars); + printvars("\tlivein", lv->livein[bb->rpo], lv->vars); + printvars("\tliveout", lv->liveout[bb->rpo], lv->vars); + printvars("\tavarinit", lv->avarinit[bb->rpo], lv->vars); + printvars("\tavarinitany", lv->avarinitany[bb->rpo], lv->vars); + printvars("\tavarinitall", lv->avarinitall[bb->rpo], lv->vars); + + print("\tprog:\n"); + for(prog = bb->first;; prog = prog->link) { + print("\t\t%P", prog); + if(prog->as == APCDATA && prog->from.offset == PCDATA_StackMapIndex) { + pos = prog->to.offset; + live = *(Bvec**)arrayget(lv->livepointers, pos); + print(" "); + bvprint(live); + } + print("\n"); + if(prog == bb->last) + break; + } +} + +// Prints a control flow graph annotated with any information computed by +// liveness analysis. +static void +livenessprintcfg(Liveness *lv) +{ + BasicBlock *bb; + int32 i; + + for(i = 0; i < arraylength(lv->cfg); i++) { + bb = *(BasicBlock**)arrayget(lv->cfg, i); + livenessprintblock(lv, bb); + } +} + +static void +checkauto(Node *fn, Prog *p, Node *n) +{ + NodeList *l; + + for(l = fn->dcl; l != nil; l = l->next) + if(l->n->op == ONAME && l->n->class == PAUTO && l->n == n) + return; + + print("checkauto %N: %N (%p; class=%d) not found in %P\n", curfn, n, n, n->class, p); + for(l = fn->dcl; l != nil; l = l->next) + print("\t%N (%p; class=%d)\n", l->n, l->n, l->n->class); + yyerror("checkauto: invariant lost"); +} + +static void +checkparam(Node *fn, Prog *p, Node *n) +{ + NodeList *l; + Node *a; + int class; + + if(isfunny(n)) + return; + for(l = fn->dcl; l != nil; l = l->next) { + a = l->n; + class = a->class & ~PHEAP; + if(a->op == ONAME && (class == PPARAM || class == PPARAMOUT) && a == n) + return; + } + + print("checkparam %N: %N (%p; class=%d) not found in %P\n", curfn, n, n, n->class, p); + for(l = fn->dcl; l != nil; l = l->next) + print("\t%N (%p; class=%d)\n", l->n, l->n, l->n->class); + yyerror("checkparam: invariant lost"); +} + +static void +checkprog(Node *fn, Prog *p) +{ + if(p->from.type == D_AUTO) + checkauto(fn, p, p->from.node); + if(p->from.type == D_PARAM) + checkparam(fn, p, p->from.node); + if(p->to.type == D_AUTO) + checkauto(fn, p, p->to.node); + if(p->to.type == D_PARAM) + checkparam(fn, p, p->to.node); +} + +// Check instruction invariants. We assume that the nodes corresponding to the +// sources and destinations of memory operations will be declared in the +// function. This is not strictly true, as is the case for the so-called funny +// nodes and there are special cases to skip over that stuff. The analysis will +// fail if this invariant blindly changes. +static void +checkptxt(Node *fn, Prog *firstp) +{ + Prog *p; + + for(p = firstp; p != P; p = p->link) { + if(0) + print("analyzing '%P'\n", p); + switch(p->as) { + case ADATA: + case AGLOBL: + case ANAME: + case ASIGNAME: + case ATYPE: + continue; + } + checkprog(fn, p); + } +} + +// NOTE: The bitmap for a specific type t should be cached in t after the first run +// and then simply copied into bv at the correct offset on future calls with +// the same type t. On https://rsc.googlecode.com/hg/testdata/slow.go, twobitwalktype1 +// accounts for 40% of the 6g execution time. +static void +twobitwalktype1(Type *t, vlong *xoffset, Bvec *bv) +{ + vlong fieldoffset; + vlong i; + vlong o; + Type *t1; + + if(t->align > 0 && (*xoffset & (t->align - 1)) != 0) + fatal("twobitwalktype1: invalid initial alignment, %T", t); + + switch(t->etype) { + case TINT8: + case TUINT8: + case TINT16: + case TUINT16: + case TINT32: + case TUINT32: + case TINT64: + case TUINT64: + case TINT: + case TUINT: + case TUINTPTR: + case TBOOL: + case TFLOAT32: + case TFLOAT64: + case TCOMPLEX64: + case TCOMPLEX128: + for(i = 0; i < t->width; i++) { + bvset(bv, ((*xoffset + i) / widthptr) * BitsPerPointer); // 1 = live scalar + } + *xoffset += t->width; + break; + + case TPTR32: + case TPTR64: + case TUNSAFEPTR: + case TFUNC: + case TCHAN: + case TMAP: + if((*xoffset & (widthptr-1)) != 0) + fatal("twobitwalktype1: invalid alignment, %T", t); + bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr + *xoffset += t->width; + break; + + case TSTRING: + // struct { byte *str; intgo len; } + if((*xoffset & (widthptr-1)) != 0) + fatal("twobitwalktype1: invalid alignment, %T", t); + bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 0); + bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 3:0 = multiword:string + *xoffset += t->width; + break; + + case TINTER: + // struct { Itab *tab; union { void *ptr, uintptr val } data; } + // or, when isnilinter(t)==true: + // struct { Type *type; union { void *ptr, uintptr val } data; } + if((*xoffset & (widthptr-1)) != 0) + fatal("twobitwalktype1: invalid alignment, %T", t); + bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 0); + bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 1); // 3 = multiword + // next word contains 2 = Iface, 3 = Eface + if(isnilinter(t)) { + bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 2); + bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 3); + } else { + bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 3); + } + *xoffset += t->width; + break; + + case TARRAY: + // The value of t->bound is -1 for slices types and >0 for + // for fixed array types. All other values are invalid. + if(t->bound < -1) + fatal("twobitwalktype1: invalid bound, %T", t); + if(isslice(t)) { + // struct { byte *array; uintgo len; uintgo cap; } + if((*xoffset & (widthptr-1)) != 0) + fatal("twobitwalktype1: invalid TARRAY alignment, %T", t); + bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 0); + bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); + bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 2); // 3:1 = multiword/slice + *xoffset += t->width; + } else + for(i = 0; i < t->bound; i++) + twobitwalktype1(t->type, xoffset, bv); + break; + + case TSTRUCT: + o = 0; + for(t1 = t->type; t1 != T; t1 = t1->down) { + fieldoffset = t1->width; + *xoffset += fieldoffset - o; + twobitwalktype1(t1->type, xoffset, bv); + o = fieldoffset + t1->type->width; + } + *xoffset += t->width - o; + break; + + default: + fatal("twobitwalktype1: unexpected type, %T", t); + } +} + +// Returns the number of words of local variables. +static int32 +localswords(void) +{ + return stkptrsize / widthptr; +} + +// Returns the number of words of in and out arguments. +static int32 +argswords(void) +{ + return curfn->type->argwid / widthptr; +} + +// Generates live pointer value maps for arguments and local variables. The +// this argument and the in arguments are always assumed live. The vars +// argument is an array of Node*s. +static void +twobitlivepointermap(Liveness *lv, Bvec *liveout, Array *vars, Bvec *args, Bvec *locals) +{ + Node *node; + Type *thisargtype; + Type *inargtype; + vlong xoffset; + int32 i; + + for(i = 0; i < arraylength(vars); i++) { + node = *(Node**)arrayget(vars, i); + switch(node->class) { + case PAUTO: + if(bvget(liveout, i)) { + xoffset = node->xoffset + stkptrsize; + twobitwalktype1(node->type, &xoffset, locals); + } + break; + case PPARAM: + case PPARAMOUT: + if(bvget(liveout, i)) { + xoffset = node->xoffset; + twobitwalktype1(node->type, &xoffset, args); + } + break; + } + } + + // The node list only contains declared names. + // If the receiver or arguments are unnamed, they will be omitted + // from the list above. Preserve those values - even though they are unused - + // in order to keep their addresses live for use in stack traces. + thisargtype = getthisx(lv->fn->type); + if(thisargtype != nil) { + xoffset = 0; + twobitwalktype1(thisargtype, &xoffset, args); + } + inargtype = getinargx(lv->fn->type); + if(inargtype != nil) { + xoffset = 0; + twobitwalktype1(inargtype, &xoffset, args); + } +} + +// Construct a disembodied instruction. +static Prog* +unlinkedprog(int as) +{ + Prog *p; + + p = mal(sizeof(*p)); + clearp(p); + p->as = as; + return p; +} + +// Construct a new PCDATA instruction associated with and for the purposes of +// covering an existing instruction. +static Prog* +newpcdataprog(Prog *prog, int32 index) +{ + Node from, to; + Prog *pcdata; + + nodconst(&from, types[TINT32], PCDATA_StackMapIndex); + nodconst(&to, types[TINT32], index); + pcdata = unlinkedprog(APCDATA); + pcdata->lineno = prog->lineno; + naddr(&from, &pcdata->from, 0); + naddr(&to, &pcdata->to, 0); + return pcdata; +} + +// Returns true for instructions that are safe points that must be annotated +// with liveness information. +static int +issafepoint(Prog *prog) +{ + return prog->as == ATEXT || prog->as == ACALL; +} + +// Initializes the sets for solving the live variables. Visits all the +// instructions in each basic block to summarizes the information at each basic +// block +static void +livenessprologue(Liveness *lv) +{ + BasicBlock *bb; + Bvec *uevar, *varkill, *avarinit; + Prog *p; + int32 i; + int32 nvars; + + nvars = arraylength(lv->vars); + uevar = bvalloc(nvars); + varkill = bvalloc(nvars); + avarinit = bvalloc(nvars); + for(i = 0; i < arraylength(lv->cfg); i++) { + bb = *(BasicBlock**)arrayget(lv->cfg, i); + // Walk the block instructions backward and update the block + // effects with the each prog effects. + for(p = bb->last; p != nil; p = p->opt) { + progeffects(p, lv->vars, uevar, varkill, avarinit); + if(debuglive >= 3) + printeffects(p, uevar, varkill, avarinit); + bvor(lv->varkill[i], lv->varkill[i], varkill); + bvandnot(lv->uevar[i], lv->uevar[i], varkill); + bvor(lv->uevar[i], lv->uevar[i], uevar); + } + // Walk the block instructions forward to update avarinit bits. + // avarinit describes the effect at the end of the block, not the beginning. + bvresetall(varkill); + for(p = bb->first;; p = p->link) { + progeffects(p, lv->vars, uevar, varkill, avarinit); + if(debuglive >= 3) + printeffects(p, uevar, varkill, avarinit); + bvandnot(lv->avarinit[i], lv->avarinit[i], varkill); + bvor(lv->avarinit[i], lv->avarinit[i], avarinit); + if(p == bb->last) + break; + } + } + free(uevar); + free(varkill); + free(avarinit); +} + +// Solve the liveness dataflow equations. +static void +livenesssolve(Liveness *lv) +{ + BasicBlock *bb, *succ, *pred; + Bvec *newlivein, *newliveout, *any, *all; + int32 rpo, i, j, change; + + // These temporary bitvectors exist to avoid successive allocations and + // frees within the loop. + newlivein = bvalloc(arraylength(lv->vars)); + newliveout = bvalloc(arraylength(lv->vars)); + any = bvalloc(arraylength(lv->vars)); + all = bvalloc(arraylength(lv->vars)); + + // Push avarinitall, avarinitany forward. + // avarinitall says the addressed var is initialized along all paths reaching the block exit. + // avarinitany says the addressed var is initialized along some path reaching the block exit. + for(i = 0; i < arraylength(lv->cfg); i++) { + bb = *(BasicBlock**)arrayget(lv->cfg, i); + rpo = bb->rpo; + if(i == 0) + bvcopy(lv->avarinitall[rpo], lv->avarinit[rpo]); + else { + bvresetall(lv->avarinitall[rpo]); + bvnot(lv->avarinitall[rpo]); + } + bvcopy(lv->avarinitany[rpo], lv->avarinit[rpo]); + } + + change = 1; + while(change != 0) { + change = 0; + for(i = 0; i < arraylength(lv->cfg); i++) { + bb = *(BasicBlock**)arrayget(lv->cfg, i); + rpo = bb->rpo; + bvresetall(any); + bvresetall(all); + for(j = 0; j < arraylength(bb->pred); j++) { + pred = *(BasicBlock**)arrayget(bb->pred, j); + if(j == 0) { + bvcopy(any, lv->avarinitany[pred->rpo]); + bvcopy(all, lv->avarinitall[pred->rpo]); + } else { + bvor(any, any, lv->avarinitany[pred->rpo]); + bvand(all, all, lv->avarinitall[pred->rpo]); + } + } + bvandnot(any, any, lv->varkill[rpo]); + bvandnot(all, all, lv->varkill[rpo]); + bvor(any, any, lv->avarinit[rpo]); + bvor(all, all, lv->avarinit[rpo]); + if(bvcmp(any, lv->avarinitany[rpo])) { + change = 1; + bvcopy(lv->avarinitany[rpo], any); + } + if(bvcmp(all, lv->avarinitall[rpo])) { + change = 1; + bvcopy(lv->avarinitall[rpo], all); + } + } + } + + // Iterate through the blocks in reverse round-robin fashion. A work + // queue might be slightly faster. As is, the number of iterations is + // so low that it hardly seems to be worth the complexity. + change = 1; + while(change != 0) { + change = 0; + // Walk blocks in the general direction of propagation. This + // improves convergence. + for(i = arraylength(lv->cfg) - 1; i >= 0; i--) { + // A variable is live on output from this block + // if it is live on input to some successor. + // + // out[b] = \bigcup_{s \in succ[b]} in[s] + bb = *(BasicBlock**)arrayget(lv->cfg, i); + rpo = bb->rpo; + bvresetall(newliveout); + for(j = 0; j < arraylength(bb->succ); j++) { + succ = *(BasicBlock**)arrayget(bb->succ, j); + bvor(newliveout, newliveout, lv->livein[succ->rpo]); + } + if(bvcmp(lv->liveout[rpo], newliveout)) { + change = 1; + bvcopy(lv->liveout[rpo], newliveout); + } + + // A variable is live on input to this block + // if it is live on output from this block and + // not set by the code in this block. + // + // in[b] = uevar[b] \cup (out[b] \setminus varkill[b]) + bvandnot(newlivein, lv->liveout[rpo], lv->varkill[rpo]); + bvor(lv->livein[rpo], newlivein, lv->uevar[rpo]); + } + } + + free(newlivein); + free(newliveout); + free(any); + free(all); +} + +// This function is slow but it is only used for generating debug prints. +// Check whether n is marked live in args/locals. +static int +islive(Node *n, Bvec *args, Bvec *locals) +{ + int i; + + switch(n->class) { + case PPARAM: + case PPARAMOUT: + for(i = 0; i < n->type->width/widthptr*BitsPerPointer; i++) + if(bvget(args, n->xoffset/widthptr*BitsPerPointer + i)) + return 1; + break; + case PAUTO: + for(i = 0; i < n->type->width/widthptr*BitsPerPointer; i++) + if(bvget(locals, (n->xoffset + stkptrsize)/widthptr*BitsPerPointer + i)) + return 1; + break; + } + return 0; +} + +// Visits all instructions in a basic block and computes a bit vector of live +// variables at each safe point locations. +static void +livenessepilogue(Liveness *lv) +{ + BasicBlock *bb, *pred; + Bvec *ambig, *livein, *liveout, *uevar, *varkill, *args, *locals, *avarinit, *any, *all; + Node *n; + Prog *p, *next; + int32 i, j, numlive, startmsg, nmsg, nvars, pos; + vlong xoffset; + char **msg; + Fmt fmt; + + nvars = arraylength(lv->vars); + livein = bvalloc(nvars); + liveout = bvalloc(nvars); + uevar = bvalloc(nvars); + varkill = bvalloc(nvars); + avarinit = bvalloc(nvars); + any = bvalloc(nvars); + all = bvalloc(nvars); + ambig = bvalloc(localswords() * BitsPerPointer); + msg = nil; + nmsg = 0; + startmsg = 0; + + for(i = 0; i < arraylength(lv->cfg); i++) { + bb = *(BasicBlock**)arrayget(lv->cfg, i); + + // Compute avarinitany and avarinitall for entry to block. + // This duplicates information known during livenesssolve + // but avoids storing two more vectors for each block. + bvresetall(any); + bvresetall(all); + for(j = 0; j < arraylength(bb->pred); j++) { + pred = *(BasicBlock**)arrayget(bb->pred, j); + if(j == 0) { + bvcopy(any, lv->avarinitany[pred->rpo]); + bvcopy(all, lv->avarinitall[pred->rpo]); + } else { + bvor(any, any, lv->avarinitany[pred->rpo]); + bvand(all, all, lv->avarinitall[pred->rpo]); + } + } + + // Walk forward through the basic block instructions and + // allocate liveness maps for those instructions that need them. + // Seed the maps with information about the addrtaken variables. + for(p = bb->first;; p = p->link) { + progeffects(p, lv->vars, uevar, varkill, avarinit); + bvandnot(any, any, varkill); + bvandnot(all, all, varkill); + bvor(any, any, avarinit); + bvor(all, all, avarinit); + + if(issafepoint(p)) { + // Annotate ambiguously live variables so that they can + // be zeroed at function entry. + // livein and liveout are dead here and used as temporaries. + // For now, only enabled when using GOEXPERIMENT=precisestack + // during make.bash / all.bash. + if(precisestack_enabled) { + bvresetall(livein); + bvandnot(liveout, any, all); + if(!bvisempty(liveout)) { + for(pos = 0; pos < liveout->n; pos++) { + if(!bvget(liveout, pos)) + continue; + bvset(all, pos); // silence future warnings in this block + n = *(Node**)arrayget(lv->vars, pos); + if(!n->needzero) { + n->needzero = 1; + if(debuglive >= 1) + warnl(p->lineno, "%N: %lN is ambiguously live", curfn->nname, n); + // Record in 'ambiguous' bitmap. + xoffset = n->xoffset + stkptrsize; + twobitwalktype1(n->type, &xoffset, ambig); + } + } + } + } + + // Allocate a bit vector for each class and facet of + // value we are tracking. + + // Live stuff first. + args = bvalloc(argswords() * BitsPerPointer); + arrayadd(lv->argslivepointers, &args); + locals = bvalloc(localswords() * BitsPerPointer); + arrayadd(lv->livepointers, &locals); + + if(debuglive >= 3) { + print("%P\n", p); + printvars("avarinitany", any, lv->vars); + } + + // Record any values with an "address taken" reaching + // this code position as live. Must do now instead of below + // because the any/all calculation requires walking forward + // over the block (as this loop does), while the liveout + // requires walking backward (as the next loop does). + twobitlivepointermap(lv, any, lv->vars, args, locals); + } + + if(p == bb->last) + break; + } + bb->lastbitmapindex = arraylength(lv->livepointers) - 1; + } + + for(i = 0; i < arraylength(lv->cfg); i++) { + bb = *(BasicBlock**)arrayget(lv->cfg, i); + + if(debuglive >= 1 && strcmp(curfn->nname->sym->name, "init") != 0 && curfn->nname->sym->name[0] != '.') { + nmsg = arraylength(lv->livepointers); + startmsg = nmsg; + msg = xmalloc(nmsg*sizeof msg[0]); + for(j=0; jlastbitmapindex; + if(pos < 0) { + // the first block we encounter should have the ATEXT so + // at no point should pos ever be less than zero. + fatal("livenessepilogue"); + } + + bvcopy(livein, lv->liveout[bb->rpo]); + for(p = bb->last; p != nil; p = next) { + next = p->opt; // splicebefore modifies p->opt + // Propagate liveness information + progeffects(p, lv->vars, uevar, varkill, avarinit); + bvcopy(liveout, livein); + bvandnot(livein, liveout, varkill); + bvor(livein, livein, uevar); + if(debuglive >= 3 && issafepoint(p)){ + print("%P\n", p); + printvars("uevar", uevar, lv->vars); + printvars("varkill", varkill, lv->vars); + printvars("livein", livein, lv->vars); + printvars("liveout", liveout, lv->vars); + } + if(issafepoint(p)) { + // Found an interesting instruction, record the + // corresponding liveness information. + + // Useful sanity check: on entry to the function, + // the only things that can possibly be live are the + // input parameters. + if(p->as == ATEXT) { + for(j = 0; j < liveout->n; j++) { + if(!bvget(liveout, j)) + continue; + n = *(Node**)arrayget(lv->vars, j); + if(n->class != PPARAM) + yyerrorl(p->lineno, "internal error: %N %lN recorded as live on entry", curfn->nname, n); + } + } + + // Record live pointers. + args = *(Bvec**)arrayget(lv->argslivepointers, pos); + locals = *(Bvec**)arrayget(lv->livepointers, pos); + twobitlivepointermap(lv, liveout, lv->vars, args, locals); + + // Ambiguously live variables are zeroed immediately after + // function entry. Mark them live for all the non-entry bitmaps + // so that GODEBUG=gcdead=1 mode does not poison them. + if(p->as == ACALL) + bvor(locals, locals, ambig); + + // Show live pointer bitmaps. + // We're interpreting the args and locals bitmap instead of liveout so that we + // include the bits added by the avarinit logic in the + // previous loop. + if(msg != nil) { + fmtstrinit(&fmt); + fmtprint(&fmt, "%L: live at ", p->lineno); + if(p->as == ACALL && p->to.node) + fmtprint(&fmt, "call to %s:", p->to.node->sym->name); + else if(p->as == ACALL) + fmtprint(&fmt, "indirect call:"); + else + fmtprint(&fmt, "entry to %s:", p->from.node->sym->name); + numlive = 0; + for(j = 0; j < arraylength(lv->vars); j++) { + n = *(Node**)arrayget(lv->vars, j); + if(islive(n, args, locals)) { + fmtprint(&fmt, " %N", n); + numlive++; + } + } + fmtprint(&fmt, "\n"); + if(numlive == 0) // squelch message + free(fmtstrflush(&fmt)); + else + msg[--startmsg] = fmtstrflush(&fmt); + } + + // Only CALL instructions need a PCDATA annotation. + // The TEXT instruction annotation is implicit. + if(p->as == ACALL) { + if(isdeferreturn(p)) { + // runtime.deferreturn modifies its return address to return + // back to the CALL, not to the subsequent instruction. + // Because the return comes back one instruction early, + // the PCDATA must begin one instruction early too. + // The instruction before a call to deferreturn is always a + // no-op, to keep PC-specific data unambiguous. + splicebefore(lv, bb, newpcdataprog(p->opt, pos), p->opt); + } else { + splicebefore(lv, bb, newpcdataprog(p, pos), p); + } + } + + pos--; + } + } + if(msg != nil) { + for(j=startmsg; jb; + ep = p + 4*((bv->n+31)/32); + while(p < ep) + h = (h*Hp) ^ *p++; + return h; +} + +// Compact liveness information by coalescing identical per-call-site bitmaps. +// The merging only happens for a single function, not across the entire binary. +// +// There are actually two lists of bitmaps, one list for the local variables and one +// list for the function arguments. Both lists are indexed by the same PCDATA +// index, so the corresponding pairs must be considered together when +// merging duplicates. The argument bitmaps change much less often during +// function execution than the local variable bitmaps, so it is possible that +// we could introduce a separate PCDATA index for arguments vs locals and +// then compact the set of argument bitmaps separately from the set of +// local variable bitmaps. As of 2014-04-02, doing this to the godoc binary +// is actually a net loss: we save about 50k of argument bitmaps but the new +// PCDATA tables cost about 100k. So for now we keep using a single index for +// both bitmap lists. +static void +livenesscompact(Liveness *lv) +{ + int *table, *remap, i, j, n, tablesize, uniq; + uint32 h; + Bvec *local, *arg, *jlocal, *jarg; + Prog *p; + + // Linear probing hash table of bitmaps seen so far. + // The hash table has 4n entries to keep the linear + // scan short. An entry of -1 indicates an empty slot. + n = arraylength(lv->livepointers); + tablesize = 4*n; + table = xmalloc(tablesize*sizeof table[0]); + memset(table, 0xff, tablesize*sizeof table[0]); + + // remap[i] = the new index of the old bit vector #i. + remap = xmalloc(n*sizeof remap[0]); + memset(remap, 0xff, n*sizeof remap[0]); + uniq = 0; // unique tables found so far + + // Consider bit vectors in turn. + // If new, assign next number using uniq, + // record in remap, record in lv->livepointers and lv->argslivepointers + // under the new index, and add entry to hash table. + // If already seen, record earlier index in remap and free bitmaps. + for(i=0; ilivepointers, i); + arg = *(Bvec**)arrayget(lv->argslivepointers, i); + h = hashbitmap(hashbitmap(H0, local), arg) % tablesize; + + for(;;) { + j = table[h]; + if(j < 0) + break; + jlocal = *(Bvec**)arrayget(lv->livepointers, j); + jarg = *(Bvec**)arrayget(lv->argslivepointers, j); + if(bvcmp(local, jlocal) == 0 && bvcmp(arg, jarg) == 0) { + free(local); + free(arg); + remap[i] = j; + goto Next; + } + if(++h == tablesize) + h = 0; + } + table[h] = uniq; + remap[i] = uniq; + *(Bvec**)arrayget(lv->livepointers, uniq) = local; + *(Bvec**)arrayget(lv->argslivepointers, uniq) = arg; + uniq++; + Next:; + } + + // We've already reordered lv->livepointers[0:uniq] + // and lv->argslivepointers[0:uniq] and freed the bitmaps + // we don't need anymore. Clear the pointers later in the + // array so that we can tell where the coalesced bitmaps stop + // and so that we don't double-free when cleaning up. + for(j=uniq; jlivepointers, j) = nil; + *(Bvec**)arrayget(lv->argslivepointers, j) = nil; + } + + // Rewrite PCDATA instructions to use new numbering. + for(p=lv->ptxt; p != P; p=p->link) { + if(p->as == APCDATA && p->from.offset == PCDATA_StackMapIndex) { + i = p->to.offset; + if(i >= 0) + p->to.offset = remap[i]; + } + } + + free(table); + free(remap); +} + +static int +printbitset(int printed, char *name, Array *vars, Bvec *bits) +{ + int i, started; + Node *n; + + started = 0; + for(i=0; isym->name); + } + return printed; +} + +// Prints the computed liveness information and inputs, for debugging. +// This format synthesizes the information used during the multiple passes +// into a single presentation. +static void +livenessprintdebug(Liveness *lv) +{ + int i, j, pcdata, printed; + BasicBlock *bb; + Prog *p; + Bvec *uevar, *varkill, *avarinit, *args, *locals; + Node *n; + + print("liveness: %s\n", curfn->nname->sym->name); + + uevar = bvalloc(arraylength(lv->vars)); + varkill = bvalloc(arraylength(lv->vars)); + avarinit = bvalloc(arraylength(lv->vars)); + + pcdata = 0; + for(i = 0; i < arraylength(lv->cfg); i++) { + if(i > 0) + print("\n"); + bb = *(BasicBlock**)arrayget(lv->cfg, i); + + // bb#0 pred=1,2 succ=3,4 + print("bb#%d pred=", i); + for(j = 0; j < arraylength(bb->pred); j++) { + if(j > 0) + print(","); + print("%d", (*(BasicBlock**)arrayget(bb->pred, j))->rpo); + } + print(" succ="); + for(j = 0; j < arraylength(bb->succ); j++) { + if(j > 0) + print(","); + print("%d", (*(BasicBlock**)arrayget(bb->succ, j))->rpo); + } + print("\n"); + + // initial settings + printed = 0; + printed = printbitset(printed, "uevar", lv->vars, lv->uevar[bb->rpo]); + printed = printbitset(printed, "livein", lv->vars, lv->livein[bb->rpo]); + if(printed) + print("\n"); + + // program listing, with individual effects listed + for(p = bb->first;; p = p->link) { + print("%P\n", p); + if(p->as == APCDATA && p->from.offset == PCDATA_StackMapIndex) + pcdata = p->to.offset; + progeffects(p, lv->vars, uevar, varkill, avarinit); + printed = 0; + printed = printbitset(printed, "uevar", lv->vars, uevar); + printed = printbitset(printed, "varkill", lv->vars, varkill); + printed = printbitset(printed, "avarinit", lv->vars, avarinit); + if(printed) + print("\n"); + if(issafepoint(p)) { + args = *(Bvec**)arrayget(lv->argslivepointers, pcdata); + locals = *(Bvec**)arrayget(lv->livepointers, pcdata); + print("\tlive="); + printed = 0; + for(j = 0; j < arraylength(lv->vars); j++) { + n = *(Node**)arrayget(lv->vars, j); + if(islive(n, args, locals)) { + if(printed++) + print(","); + print("%N", n); + } + } + print("\n"); + } + if(p == bb->last) + break; + } + + // bb bitsets + print("end\n"); + printed = printbitset(printed, "varkill", lv->vars, lv->varkill[bb->rpo]); + printed = printbitset(printed, "liveout", lv->vars, lv->liveout[bb->rpo]); + printed = printbitset(printed, "avarinit", lv->vars, lv->avarinit[bb->rpo]); + printed = printbitset(printed, "avarinitany", lv->vars, lv->avarinitany[bb->rpo]); + printed = printbitset(printed, "avarinitall", lv->vars, lv->avarinitall[bb->rpo]); + if(printed) + print("\n"); + } + print("\n"); + + free(uevar); + free(varkill); + free(avarinit); +} + +// Dumps an array of bitmaps to a symbol as a sequence of uint32 values. The +// first word dumped is the total number of bitmaps. The second word is the +// length of the bitmaps. All bitmaps are assumed to be of equal length. The +// words that are followed are the raw bitmap words. The arr argument is an +// array of Node*s. +static void +twobitwritesymbol(Array *arr, Sym *sym) +{ + Bvec *bv; + int off, i, j, len; + uint32 word; + + len = arraylength(arr); + off = 0; + off += 4; // number of bitmaps, to fill in later + bv = *(Bvec**)arrayget(arr, 0); + off = duint32(sym, off, bv->n); // number of bits in each bitmap + for(i = 0; i < len; i++) { + // bitmap words + bv = *(Bvec**)arrayget(arr, i); + if(bv == nil) + break; + for(j = 0; j < bv->n; j += 32) { + word = bv->b[j/32]; + off = duint32(sym, off, word); + } + } + duint32(sym, 0, i); // number of bitmaps + ggloblsym(sym, off, 0, 1); +} + +static void +printprog(Prog *p) +{ + while(p != nil) { + print("%P\n", p); + p = p->link; + } +} + +// Entry pointer for liveness analysis. Constructs a complete CFG, solves for +// the liveness of pointer variables in the function, and emits a runtime data +// structure read by the garbage collector. +void +liveness(Node *fn, Prog *firstp, Sym *argssym, Sym *livesym) +{ + Array *cfg, *vars; + Liveness *lv; + int debugdelta; + + // Change name to dump debugging information only for a specific function. + debugdelta = 0; + if(strcmp(curfn->nname->sym->name, "!") == 0) + debugdelta = 2; + + debuglive += debugdelta; + if(debuglive >= 3) { + print("liveness: %s\n", curfn->nname->sym->name); + printprog(firstp); + } + checkptxt(fn, firstp); + + // Construct the global liveness state. + cfg = newcfg(firstp); + if(debuglive >= 3) + printcfg(cfg); + vars = getvariables(fn); + lv = newliveness(fn, firstp, cfg, vars); + + // Run the dataflow framework. + livenessprologue(lv); + if(debuglive >= 3) + livenessprintcfg(lv); + livenesssolve(lv); + if(debuglive >= 3) + livenessprintcfg(lv); + livenessepilogue(lv); + if(debuglive >= 3) + livenessprintcfg(lv); + livenesscompact(lv); + + if(debuglive >= 2) + livenessprintdebug(lv); + + // Emit the live pointer map data structures + twobitwritesymbol(lv->livepointers, livesym); + twobitwritesymbol(lv->argslivepointers, argssym); + + // Free everything. + freeliveness(lv); + arrayfree(vars); + freecfg(cfg); + + debuglive -= debugdelta; +} diff --git a/src/cmd/gc/popt.c b/src/cmd/gc/popt.c index 8d7afa011..ea88b94db 100644 --- a/src/cmd/gc/popt.c +++ b/src/cmd/gc/popt.c @@ -51,9 +51,14 @@ noreturn(Prog *p) symlist[2] = pkglookup("throwinit", runtimepkg); symlist[3] = pkglookup("panic", runtimepkg); symlist[4] = pkglookup("panicwrap", runtimepkg); + symlist[5] = pkglookup("throwreturn", runtimepkg); + symlist[6] = pkglookup("selectgo", runtimepkg); + symlist[7] = pkglookup("block", runtimepkg); } - s = p->to.sym; + if(p->to.node == nil) + return 0; + s = p->to.node->sym; if(s == S) return 0; for(i=0; symlist[i]!=S; i++) @@ -144,7 +149,13 @@ fixjmp(Prog *firstp) if(p->opt == dead) { if(p->link == P && p->as == ARET && last && last->as != ARET) { // This is the final ARET, and the code so far doesn't have one. - // Let it stay. + // Let it stay. The register allocator assumes that all live code in + // the function can be traversed by starting at all the RET instructions + // and following predecessor links. If we remove the final RET, + // this assumption will not hold in the case of an infinite loop + // at the end of a function. + // Keep the RET but mark it dead for the liveness analysis. + p->mode = 1; } else { if(debug['R'] && debug['v']) print("del %P\n", p); @@ -489,8 +500,8 @@ struct TempVar TempFlow *use; // use list, chained through TempFlow.uselink TempVar *freelink; // next free temp in Type.opt list TempVar *merge; // merge var with this one - uint32 start; // smallest Prog.loc in live range - uint32 end; // largest Prog.loc in live range + vlong start; // smallest Prog.pc in live range + vlong end; // largest Prog.pc in live range uchar addr; // address taken - no accurate end uchar removed; // removed from program }; @@ -520,10 +531,11 @@ startcmp(const void *va, const void *vb) static int canmerge(Node *n) { - return n->class == PAUTO && !n->addrtaken && strncmp(n->sym->name, "autotmp", 7) == 0; + return n->class == PAUTO && strncmp(n->sym->name, "autotmp", 7) == 0; } static void mergewalk(TempVar*, TempFlow*, uint32); +static void varkillwalk(TempVar*, TempFlow*, uint32); void mergetemp(Prog *firstp) @@ -544,7 +556,7 @@ mergetemp(Prog *firstp) g = flowstart(firstp, sizeof(TempFlow)); if(g == nil) return; - + // Build list of all mergeable variables. nvar = 0; for(l = curfn->dcl; l != nil; l = l->next) @@ -640,6 +652,11 @@ mergetemp(Prog *firstp) gen++; for(r = v->use; r != nil; r = r->uselink) mergewalk(v, r, gen); + if(v->addr) { + gen++; + for(r = v->use; r != nil; r = r->uselink) + varkillwalk(v, r, gen); + } } // Sort variables by start. @@ -659,7 +676,7 @@ mergetemp(Prog *firstp) nfree = nvar; for(i=0; iaddr || v->removed) + if(v->removed) continue; // Expire no longer in use. @@ -672,7 +689,12 @@ mergetemp(Prog *firstp) t = v->node->type; for(j=nfree; jnode->type)) { + // Require the types to match but also require the addrtaken bits to match. + // If a variable's address is taken, that disables registerization for the individual + // words of the variable (for example, the base,len,cap of a slice). + // We don't want to merge a non-addressed var with an addressed one and + // inhibit registerization of the former. + if(eqtype(t, v1->node->type) && v->node->addrtaken == v1->node->addrtaken) { inuse[j] = inuse[nfree++]; if(v1->merge) v->merge = v1->merge; @@ -695,7 +717,7 @@ mergetemp(Prog *firstp) if(Debug) { print("%S [%d - %d]\n", curfn->nname->sym, nvar, nkill); for(v=var; vnode, v->node->type, v->start, v->end); + print("var %#N %T %lld-%lld", v->node, v->node->type, v->start, v->end); if(v->addr) print(" addr=1"); if(v->removed) @@ -752,10 +774,10 @@ mergewalk(TempVar *v, TempFlow *r0, uint32 gen) break; r1->f.active = gen; p = r1->f.prog; - if(v->end < p->loc) - v->end = p->loc; + if(v->end < p->pc) + v->end = p->pc; if(r1 == v->def) { - v->start = p->loc; + v->start = p->pc; break; } } @@ -765,6 +787,29 @@ mergewalk(TempVar *v, TempFlow *r0, uint32 gen) mergewalk(v, r2, gen); } +static void +varkillwalk(TempVar *v, TempFlow *r0, uint32 gen) +{ + Prog *p; + TempFlow *r1, *r; + + for(r1 = r0; r1 != nil; r1 = (TempFlow*)r1->f.s1) { + if(r1->f.active == gen) + break; + r1->f.active = gen; + p = r1->f.prog; + if(v->end < p->pc) + v->end = p->pc; + if(v->start > p->pc) + v->start = p->pc; + if(p->as == ARET || (p->as == AVARKILL && p->to.node == v->node)) + break; + } + + for(r = r0; r != r1; r = (TempFlow*)r->f.s1) + varkillwalk(v, (TempFlow*)r->f.s2, gen); +} + // Eliminate redundant nil pointer checks. // // The code generation pass emits a CHECKNIL for every possibly nil pointer. @@ -911,7 +956,7 @@ nilwalkback(NilFlow *rcheck) static void nilwalkfwd(NilFlow *rcheck) { - NilFlow *r; + NilFlow *r, *last; Prog *p; ProgInfo info; @@ -922,6 +967,7 @@ nilwalkfwd(NilFlow *rcheck) // avoid problems like: // _ = *x // should panic // for {} // no writes but infinite loop may be considered visible + last = nil; for(r = (NilFlow*)uniqs(&rcheck->f); r != nil; r = (NilFlow*)uniqs(&r->f)) { p = r->f.prog; proginfo(&info, p); @@ -944,5 +990,12 @@ nilwalkfwd(NilFlow *rcheck) // Stop if memory write. if((info.flags & RightWrite) && !regtyp(&p->to)) return; + // Stop if we jump backward. + // This test is valid because all the NilFlow* are pointers into + // a single contiguous array. We will need to add an explicit + // numbering when the code is converted to Go. + if(last != nil && r <= last) + return; + last = r; } } diff --git a/src/cmd/gc/racewalk.c b/src/cmd/gc/racewalk.c index d6a5b3cce..285bd78a2 100644 --- a/src/cmd/gc/racewalk.c +++ b/src/cmd/gc/racewalk.c @@ -166,6 +166,7 @@ racewalknode(Node **np, NodeList **init, int wr, int skip) goto ret; case OCFUNC: + case OVARKILL: // can't matter goto ret; @@ -181,7 +182,7 @@ racewalknode(Node **np, NodeList **init, int wr, int skip) // x, y := f() becomes BLOCK{CALL f, AS x [SP+0], AS y [SP+n]} // We don't want to instrument between the statements because it will // smash the results. - racewalknode(&n->list->n, &n->ninit, 0, 0); + racewalknode(&n->list->n, &n->list->n->ninit, 0, 0); fini = nil; racewalklist(n->list->next, &fini); n->list = concat(n->list, fini); diff --git a/src/cmd/gc/range.c b/src/cmd/gc/range.c index bd271da38..45aa521b3 100644 --- a/src/cmd/gc/range.c +++ b/src/cmd/gc/range.c @@ -111,6 +111,8 @@ walkrange(Node *n) Node *hb; // hidden bool Node *a, *v1, *v2; // not hidden aggregate, val 1, 2 Node *fn, *tmp; + Node *keyname, *valname; + Node *key, *val; NodeList *body, *init; Type *th, *t; int lno; @@ -120,34 +122,23 @@ walkrange(Node *n) a = n->right; lno = setlineno(a); - if(t->etype == TSTRING && !eqtype(t, types[TSTRING])) { - a = nod(OCONV, n->right, N); - a->type = types[TSTRING]; - } v1 = n->list->n; v2 = N; - if(n->list->next) + if(n->list->next && !isblank(n->list->next->n)) v2 = n->list->next->n; // n->list has no meaning anymore, clear it // to avoid erroneous processing by racewalk. n->list = nil; 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 = temp(a->type); - init = list(init, nod(OAS, ha, a)); - } - switch(t->etype) { default: fatal("walkrange"); case TARRAY: + // orderstmt arranged for a copy of the array/slice variable if needed. + ha = a; hv1 = temp(types[TINT]); hn = temp(types[TINT]); hp = nil; @@ -162,8 +153,7 @@ walkrange(Node *n) } n->ntest = nod(OLT, hv1, hn); - n->nincr = nod(OASOP, hv1, nodintconst(1)); - n->nincr->etype = OADD; + n->nincr = nod(OAS, hv1, nod(OADD, hv1, nodintconst(1))); if(v2 == N) body = list1(nod(OAS, v1, hv1)); else { @@ -171,54 +161,70 @@ walkrange(Node *n) a->list = list(list1(v1), v2); a->rlist = list(list1(hv1), nod(OIND, hp, N)); body = list1(a); - + + // Advance pointer as part of increment. + // We used to advance the pointer before executing the loop body, + // but doing so would make the pointer point past the end of the + // array during the final iteration, possibly causing another unrelated + // piece of memory not to be garbage collected until the loop finished. + // Advancing during the increment ensures that the pointer p only points + // pass the end of the array during the final "p++; i++; if(i >= len(x)) break;", + // after which p is dead, so it cannot confuse the collector. tmp = nod(OADD, hp, nodintconst(t->type->width)); tmp->type = hp->type; tmp->typecheck = 1; tmp->right->type = types[tptr]; tmp->right->typecheck = 1; - body = list(body, nod(OAS, hp, tmp)); + a = nod(OAS, hp, tmp); + typecheck(&a, Etop); + n->nincr->ninit = list1(a); } break; case TMAP: - th = typ(TARRAY); - th->type = ptrto(types[TUINT8]); - // see ../../pkg/runtime/hashmap.c:/hash_iter - // Size of hash_iter in # of pointers. - th->bound = 11; - hit = temp(th); + // orderstmt allocated the iterator for us. + // we only use a once, so no copy needed. + ha = a; + th = hiter(t); + hit = n->alloc; + hit->type = th; + n->left = N; + keyname = newname(th->type->sym); // depends on layout of iterator struct. See reflect.c:hiter + valname = newname(th->type->down->sym); // ditto fn = syslook("mapiterinit", 1); argtype(fn, t->down); argtype(fn, t->type); argtype(fn, th); init = list(init, mkcall1(fn, T, nil, typename(t), ha, nod(OADDR, hit, N))); - n->ntest = nod(ONE, nod(OINDEX, hit, nodintconst(0)), nodnil()); + n->ntest = nod(ONE, nod(ODOT, hit, keyname), nodnil()); fn = syslook("mapiternext", 1); argtype(fn, th); n->nincr = mkcall1(fn, T, nil, nod(OADDR, hit, N)); + key = nod(ODOT, hit, keyname); + key = nod(OIND, key, N); if(v2 == N) { - fn = syslook("mapiter1", 1); - argtype(fn, th); - argtype(fn, t->down); - a = nod(OAS, v1, mkcall1(fn, t->down, nil, nod(OADDR, hit, N))); + a = nod(OAS, v1, key); } else { - fn = syslook("mapiter2", 1); - argtype(fn, th); - argtype(fn, t->down); - argtype(fn, t->type); + val = nod(ODOT, hit, valname); + val = nod(OIND, val, N); a = nod(OAS2, N, N); a->list = list(list1(v1), v2); - a->rlist = list1(mkcall1(fn, getoutargx(fn->type), nil, nod(OADDR, hit, N))); + a->rlist = list(list1(key), val); } body = list1(a); break; case TCHAN: + // orderstmt arranged for a copy of the channel variable. + ha = a; + n->ntest = N; + hv1 = temp(t->type); + if(haspointers(t->type)) + init = list(init, nod(OAS, hv1, N)); hb = temp(types[TBOOL]); n->ntest = nod(ONE, hb, nodbool(0)); @@ -231,6 +237,9 @@ walkrange(Node *n) break; case TSTRING: + // orderstmt arranged for a copy of the string variable. + ha = a; + ohv1 = temp(types[TINT]); hv1 = temp(types[TINT]); diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c index 0a8aa8d7a..dbb447e4e 100644 --- a/src/cmd/gc/reflect.c +++ b/src/cmd/gc/reflect.c @@ -125,6 +125,8 @@ mapbucket(Type *t) keytype = t->down; valtype = t->type; + dowidth(keytype); + dowidth(valtype); if(keytype->width > MAXKEYSIZE) keytype = ptrto(keytype); if(valtype->width > MAXVALSIZE) @@ -143,6 +145,11 @@ mapbucket(Type *t) overflowfield->sym = mal(sizeof(Sym)); // not important but needs to be set to give this type a name overflowfield->sym->name = "overflow"; offset += widthptr; + + // The keys are padded to the native integer alignment. + // This is usually the same as widthptr; the exception (as usual) is nacl/amd64. + if(widthreg > widthptr) + offset += widthreg - widthptr; keysfield = typ(TFIELD); keysfield->type = typ(TARRAY); @@ -173,6 +180,7 @@ mapbucket(Type *t) bucket->width = offset; bucket->local = t->local; t->bucket = bucket; + bucket->map = t; return bucket; } @@ -229,10 +237,89 @@ hmap(Type *t) h->width = offset; h->local = t->local; t->hmap = h; - h->hmap = t; + h->map = t; return h; } +Type* +hiter(Type *t) +{ + int32 n, off; + Type *field[7]; + Type *i; + + if(t->hiter != T) + return t->hiter; + + // build a struct: + // hash_iter { + // key *Key + // val *Value + // t *MapType + // h *Hmap + // buckets *Bucket + // bptr *Bucket + // other [4]uintptr + // } + // must match ../../pkg/runtime/hashmap.c:hash_iter. + field[0] = typ(TFIELD); + field[0]->type = ptrto(t->down); + field[0]->sym = mal(sizeof(Sym)); + field[0]->sym->name = "key"; + + field[1] = typ(TFIELD); + field[1]->type = ptrto(t->type); + field[1]->sym = mal(sizeof(Sym)); + field[1]->sym->name = "val"; + + field[2] = typ(TFIELD); + field[2]->type = ptrto(types[TUINT8]); // TODO: is there a Type type? + field[2]->sym = mal(sizeof(Sym)); + field[2]->sym->name = "t"; + + field[3] = typ(TFIELD); + field[3]->type = ptrto(hmap(t)); + field[3]->sym = mal(sizeof(Sym)); + field[3]->sym->name = "h"; + + field[4] = typ(TFIELD); + field[4]->type = ptrto(mapbucket(t)); + field[4]->sym = mal(sizeof(Sym)); + field[4]->sym->name = "buckets"; + + field[5] = typ(TFIELD); + field[5]->type = ptrto(mapbucket(t)); + field[5]->sym = mal(sizeof(Sym)); + field[5]->sym->name = "bptr"; + + // all other non-pointer fields + field[6] = typ(TFIELD); + field[6]->type = typ(TARRAY); + field[6]->type->type = types[TUINTPTR]; + field[6]->type->bound = 4; + field[6]->type->width = 4 * widthptr; + field[6]->sym = mal(sizeof(Sym)); + field[6]->sym->name = "other"; + + // build iterator struct holding the above fields + i = typ(TSTRUCT); + i->noalg = 1; + i->type = field[0]; + off = 0; + for(n = 0; n < 6; n++) { + field[n]->down = field[n+1]; + field[n]->width = off; + off += field[n]->type->width; + } + field[6]->down = T; + off += field[6]->type->width; + if(off != 10 * widthptr) + yyerror("hash_iter size not correct %d %d", off, 10 * widthptr); + t->hiter = i; + i->map = t; + return i; +} + /* * f is method type, with receiver. * return function type, receiver as first argument (or not). @@ -396,9 +483,8 @@ imethods(Type *t) last->link = a; last = a; - // Compiler can only refer to wrappers for - // named interface types and non-blank methods. - if(t->sym == S || isblanksym(method)) + // Compiler can only refer to wrappers for non-blank methods. + if(isblanksym(method)) continue; // NOTE(rsc): Perhaps an oversight that @@ -620,6 +706,10 @@ haspointers(Type *t) ret = 1; break; } + if(t->bound == 0) { // empty array + ret = 0; + break; + } ret = haspointers(t->type); break; case TSTRUCT: @@ -656,7 +746,7 @@ static int dcommontype(Sym *s, int ot, Type *t) { int i, alg, sizeofAlg; - Sym *sptr, *algsym; + Sym *sptr, *algsym, *zero; static Sym *algarray; char *p; @@ -677,6 +767,18 @@ dcommontype(Sym *s, int ot, Type *t) else sptr = weaktypesym(ptrto(t)); + // All (non-reflect-allocated) Types share the same zero object. + // Each place in the compiler where a pointer to the zero object + // might be returned by a runtime call (map access return value, + // 2-arg type cast) declares the size of the zerovalue it needs. + // The linker magically takes the max of all the sizes. + zero = pkglookup("zerovalue", runtimepkg); + + // We use size 0 here so we get the pointer to the zero value, + // but don't allocate space for the zero value unless we need it. + // TODO: how do we get this symbol into bss? We really want + // a read-only bss, but I don't think such a thing exists. + // ../../pkg/reflect/type.go:/^type.commonType // actual type structure // type commonType struct { @@ -691,6 +793,7 @@ dcommontype(Sym *s, int ot, Type *t) // string *string // *extraType // ptrToThis *Type + // zero unsafe.Pointer // } ot = duintptr(s, ot, t->width); ot = duint32(s, ot, typehash(t)); @@ -728,6 +831,7 @@ dcommontype(Sym *s, int ot, Type *t) ot += widthptr; ot = dsymptr(s, ot, sptr, 0); // ptrto type + ot = dsymptr(s, ot, zero, 0); // ptr to zero value return ot; } @@ -893,7 +997,7 @@ ok: switch(t->etype) { default: ot = dcommontype(s, ot, t); - xt = ot - 2*widthptr; + xt = ot - 3*widthptr; break; case TARRAY: @@ -905,7 +1009,7 @@ ok: t2->bound = -1; // slice s2 = dtypesym(t2); ot = dcommontype(s, ot, t); - xt = ot - 2*widthptr; + xt = ot - 3*widthptr; ot = dsymptr(s, ot, s1, 0); ot = dsymptr(s, ot, s2, 0); ot = duintptr(s, ot, t->bound); @@ -913,7 +1017,7 @@ ok: // ../../pkg/runtime/type.go:/SliceType s1 = dtypesym(t->type); ot = dcommontype(s, ot, t); - xt = ot - 2*widthptr; + xt = ot - 3*widthptr; ot = dsymptr(s, ot, s1, 0); } break; @@ -922,7 +1026,7 @@ ok: // ../../pkg/runtime/type.go:/ChanType s1 = dtypesym(t->type); ot = dcommontype(s, ot, t); - xt = ot - 2*widthptr; + xt = ot - 3*widthptr; ot = dsymptr(s, ot, s1, 0); ot = duintptr(s, ot, t->chan); break; @@ -939,7 +1043,7 @@ ok: dtypesym(t1->type); ot = dcommontype(s, ot, t); - xt = ot - 2*widthptr; + xt = ot - 3*widthptr; ot = duint8(s, ot, isddd); // two slice headers: in and out. @@ -971,7 +1075,7 @@ ok: // ../../pkg/runtime/type.go:/InterfaceType ot = dcommontype(s, ot, t); - xt = ot - 2*widthptr; + xt = ot - 3*widthptr; ot = dsymptr(s, ot, s, ot+widthptr+2*widthint); ot = duintxx(s, ot, n, widthint); ot = duintxx(s, ot, n, widthint); @@ -990,7 +1094,7 @@ ok: s3 = dtypesym(mapbucket(t)); s4 = dtypesym(hmap(t)); ot = dcommontype(s, ot, t); - xt = ot - 2*widthptr; + xt = ot - 3*widthptr; ot = dsymptr(s, ot, s1, 0); ot = dsymptr(s, ot, s2, 0); ot = dsymptr(s, ot, s3, 0); @@ -1007,7 +1111,7 @@ ok: // ../../pkg/runtime/type.go:/PtrType s1 = dtypesym(t->type); ot = dcommontype(s, ot, t); - xt = ot - 2*widthptr; + xt = ot - 3*widthptr; ot = dsymptr(s, ot, s1, 0); break; @@ -1020,7 +1124,7 @@ ok: n++; } ot = dcommontype(s, ot, t); - xt = ot - 2*widthptr; + xt = ot - 3*widthptr; ot = dsymptr(s, ot, s, ot+widthptr+2*widthint); ot = duintxx(s, ot, n, widthint); ot = duintxx(s, ot, n, widthint); @@ -1218,7 +1322,22 @@ dgcsym1(Sym *s, int ot, Type *t, vlong *off, int stack_size) // NOTE: Any changes here need to be made to reflect.PtrTo as well. if(*off % widthptr != 0) fatal("dgcsym1: invalid alignment, %T", t); - if(!haspointers(t->type) || t->type->etype == TUINT8) { + + // NOTE(rsc): Emitting GC_APTR here for *nonptrtype + // (pointer to non-pointer-containing type) means that + // we do not record 'nonptrtype' and instead tell the + // garbage collector to look up the type of the memory in + // type information stored in the heap. In effect we are telling + // the collector "we don't trust our information - use yours". + // It's not completely clear why we want to do this. + // It does have the effect that if you have a *SliceHeader and a *[]int + // pointing at the same actual slice header, *SliceHeader will not be + // used as an authoritative type for the memory, which is good: + // if the collector scanned the memory as type *SliceHeader, it would + // see no pointers inside but mark the block as scanned, preventing + // the seeing of pointers when we followed the *[]int pointer. + // Perhaps that kind of situation is the rationale. + if(!haspointers(t->type)) { ot = duintptr(s, ot, GC_APTR); ot = duintptr(s, ot, *off); } else { diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go index c8d57ab33..fb5c2a150 100644 --- a/src/cmd/gc/runtime.go +++ b/src/cmd/gc/runtime.go @@ -15,6 +15,7 @@ package PACKAGE func new(typ *byte) *any func panicindex() func panicslice() +func panicdivide() func throwreturn() func throwinit() func panicwrap(string, string, string) @@ -36,13 +37,17 @@ func printnl() func printsp() func goprintf() -// filled in by compiler: int n, string, string, ... -func concatstring() +func concatstring2(string, string) string +func concatstring3(string, string, string) string +func concatstring4(string, string, string, string) string +func concatstring5(string, string, string, string, string) string +func concatstrings([]string) string func cmpstring(string, string) int func eqstring(string, string) bool func intstring(int64) string func slicebytetostring([]byte) string +func slicebytetostringtmp([]byte) string func slicerunetostring([]rune) string func stringtoslicebyte(string) []byte func stringtoslicerune(string) []rune @@ -55,8 +60,8 @@ func slicestringcopy(to any, fr any) int func typ2Itab(typ *byte, typ2 *byte, cache **byte) (ret *byte) func convI2E(elem any) (ret any) func convI2I(typ *byte, elem any) (ret any) -func convT2E(typ *byte, elem any) (ret any) -func convT2I(typ *byte, typ2 *byte, cache **byte, elem any) (ret any) +func convT2E(typ *byte, elem *any) (ret any) +func convT2I(typ *byte, typ2 *byte, cache **byte, elem *any) (ret any) // interface type assertions x.(T) func assertE2E(typ *byte, iface any) (ret any) @@ -83,29 +88,27 @@ func equal(typ *byte, x1, x2 any) (ret bool) // *byte is really *runtime.Type func makemap(mapType *byte, hint int64) (hmap map[any]any) -func mapaccess1(mapType *byte, hmap map[any]any, key any) (val any) +func mapaccess1(mapType *byte, hmap map[any]any, key *any) (val *any) func mapaccess1_fast32(mapType *byte, hmap map[any]any, key any) (val *any) func mapaccess1_fast64(mapType *byte, hmap map[any]any, key any) (val *any) func mapaccess1_faststr(mapType *byte, hmap map[any]any, key any) (val *any) -func mapaccess2(mapType *byte, hmap map[any]any, key any) (val any, pres bool) +func mapaccess2(mapType *byte, hmap map[any]any, key *any) (val *any, pres bool) func mapaccess2_fast32(mapType *byte, hmap map[any]any, key any) (val *any, pres bool) func mapaccess2_fast64(mapType *byte, hmap map[any]any, key any) (val *any, pres bool) func mapaccess2_faststr(mapType *byte, hmap map[any]any, key any) (val *any, pres bool) -func mapassign1(mapType *byte, hmap map[any]any, key any, val any) +func mapassign1(mapType *byte, hmap map[any]any, key *any, val *any) func mapiterinit(mapType *byte, hmap map[any]any, hiter *any) -func mapdelete(mapType *byte, hmap map[any]any, key any) +func mapdelete(mapType *byte, hmap map[any]any, key *any) func mapiternext(hiter *any) -func mapiter1(hiter *any) (key any) -func mapiter2(hiter *any) (key any, val any) // *byte is really *runtime.Type func makechan(chanType *byte, hint int64) (hchan chan any) -func chanrecv1(chanType *byte, hchan <-chan any) (elem any) -func chanrecv2(chanType *byte, hchan <-chan any) (elem any, received bool) -func chansend1(chanType *byte, hchan chan<- any, elem any) +func chanrecv1(chanType *byte, hchan <-chan any, elem *any) +func chanrecv2(chanType *byte, hchan <-chan any, elem *any) bool +func chansend1(chanType *byte, hchan chan<- any, elem *any) func closechan(hchan any) -func selectnbsend(chanType *byte, hchan chan<- any, elem any) bool +func selectnbsend(chanType *byte, hchan chan<- any, elem *any) bool func selectnbrecv(chanType *byte, elem *any, hchan <-chan any) bool func selectnbrecv2(chanType *byte, elem *any, received *bool, hchan <-chan any) bool diff --git a/src/cmd/gc/select.c b/src/cmd/gc/select.c index cd3de8c7b..58a120674 100644 --- a/src/cmd/gc/select.c +++ b/src/cmd/gc/select.c @@ -69,6 +69,7 @@ typecheckselect(Node *sel) n->op = OSELRECV2; n->left = n->list->n; n->ntest = n->list->next->n; + n->list = nil; n->right = n->rlist->n; n->rlist = nil; break; @@ -94,7 +95,7 @@ void walkselect(Node *sel) { int lno, i; - Node *n, *r, *a, *tmp, *var, *cas, *dflt, *ch; + Node *n, *r, *a, *var, *cas, *dflt, *ch; NodeList *l, *init; if(sel->list == nil && sel->xoffset != 0) @@ -110,6 +111,8 @@ walkselect(Node *sel) } // optimization: one-case select: single op. + // TODO(rsc): Reenable optimization once order.c can handle it. + // golang.org/issue/7672. if(i == 1) { cas = sel->list->n; setlineno(cas); @@ -123,32 +126,34 @@ walkselect(Node *sel) fatal("select %O", n->op); case OSEND: - ch = cheapexpr(n->left, &l); - n->left = ch; + // ok already + ch = n->left; break; case OSELRECV: - r = n->right; - ch = cheapexpr(r->left, &l); - r->left = ch; - + ch = n->right->left; + Selrecv1: if(n->left == N) - n = r; - else { - n = nod(OAS, n->left, r); - typecheck(&n, Etop); - } + n = n->right; + else + n->op = OAS; break; case OSELRECV2: - r = n->right; - ch = cheapexpr(r->left, &l); - r->left = ch; - - a = nod(OAS2, N, N); - a->list = n->list; - a->rlist = list1(n->right); - n = a; + ch = n->right->left; + if(n->ntest == N) + goto Selrecv1; + if(n->left == N) { + typecheck(&nblank, Erv | Easgn); + n->left = nblank; + } + n->op = OAS2; + n->list = list(list1(n->left), n->ntest); + n->rlist = list1(n->right); + n->right = N; + n->left = N; + n->ntest = N; + n->typecheck = 0; typecheck(&n, Etop); break; } @@ -166,7 +171,7 @@ walkselect(Node *sel) goto out; } - // introduce temporary variables for OSELRECV where needed. + // convert case value arguments to addresses. // this rewrite is used by both the general code and the next optimization. for(l=sel->list; l; l=l->next) { cas = l->n; @@ -175,58 +180,24 @@ walkselect(Node *sel) if(n == N) continue; switch(n->op) { + case OSEND: + n->right = nod(OADDR, n->right, N); + typecheck(&n->right, Erv); + break; case OSELRECV: case OSELRECV2: - ch = n->right->left; - - // If we can use the address of the target without - // violating addressability or order of operations, do so. - // Otherwise introduce a temporary. - // Also introduce a temporary for := variables that escape, - // so that we can delay the heap allocation until the case - // is selected. + if(n->op == OSELRECV2 && n->ntest == N) + n->op = OSELRECV; if(n->op == OSELRECV2) { - if(n->ntest == N || isblank(n->ntest)) - n->ntest = nodnil(); - else if(n->ntest->op == ONAME && - (!n->colas || (n->ntest->class&PHEAP) == 0) && - convertop(types[TBOOL], n->ntest->type, nil) == OCONVNOP) { - n->ntest = nod(OADDR, n->ntest, N); - n->ntest->etype = 1; // pointer does not escape - typecheck(&n->ntest, Erv); - } else { - tmp = temp(types[TBOOL]); - a = nod(OADDR, tmp, N); - a->etype = 1; // pointer does not escape - typecheck(&a, Erv); - r = nod(OAS, n->ntest, tmp); - typecheck(&r, Etop); - cas->nbody = concat(list1(r), cas->nbody); - n->ntest = a; - } + n->ntest = nod(OADDR, n->ntest, N); + typecheck(&n->ntest, Erv); } - - if(n->left == N || isblank(n->left)) + if(n->left == N) n->left = nodnil(); - else if(n->left->op == ONAME && - (!n->colas || (n->left->class&PHEAP) == 0) && - convertop(ch->type->type, n->left->type, nil) == OCONVNOP) { + else { n->left = nod(OADDR, n->left, N); - n->left->etype = 1; // pointer does not escape typecheck(&n->left, Erv); - } else { - tmp = temp(ch->type->type); - a = nod(OADDR, tmp, N); - a->etype = 1; // pointer does not escape - typecheck(&a, Erv); - r = nod(OAS, n->left, tmp); - typecheck(&r, Etop); - cas->nbody = concat(list1(r), cas->nbody); - n->left = a; - } - - cas->nbody = concat(n->ninit, cas->nbody); - n->ninit = nil; + } break; } } @@ -250,8 +221,8 @@ walkselect(Node *sel) fatal("select %O", n->op); case OSEND: - // if c != nil && selectnbsend(c, v) { body } else { default body } - ch = cheapexpr(n->left, &r->ninit); + // if selectnbsend(c, v) { body } else { default body } + ch = n->left; r->ntest = mkcall1(chanfn("selectnbsend", 2, ch->type), types[TBOOL], &r->ninit, typename(ch->type), ch, n->right); break; @@ -260,7 +231,7 @@ walkselect(Node *sel) // if c != nil && selectnbrecv(&v, c) { body } else { default body } r = nod(OIF, N, N); r->ninit = cas->ninit; - ch = cheapexpr(n->right->left, &r->ninit); + ch = n->right->left; r->ntest = mkcall1(chanfn("selectnbrecv", 2, ch->type), types[TBOOL], &r->ninit, typename(ch->type), n->left, ch); break; @@ -269,7 +240,7 @@ walkselect(Node *sel) // if c != nil && selectnbrecv2(&v, c) { body } else { default body } r = nod(OIF, N, N); r->ninit = cas->ninit; - ch = cheapexpr(n->right->left, &r->ninit); + ch = n->right->left; r->ntest = mkcall1(chanfn("selectnbrecv2", 2, ch->type), types[TBOOL], &r->ninit, typename(ch->type), n->left, n->ntest, ch); break; @@ -313,11 +284,6 @@ walkselect(Node *sel) case OSEND: // selectsend(sel *byte, hchan *chan any, elem *any) (selected bool); - n->left = localexpr(safeexpr(n->left, &r->ninit), n->left->type, &r->ninit); - n->right = localexpr(n->right, n->left->type->type, &r->ninit); - n->right = nod(OADDR, n->right, N); - n->right->etype = 1; // pointer does not escape - typecheck(&n->right, Erv); r->ntest = mkcall1(chanfn("selectsend", 2, n->left->type), types[TBOOL], &r->ninit, var, n->left, n->right); break; diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c index 446b1110a..59804cd8d 100644 --- a/src/cmd/gc/sinit.c +++ b/src/cmd/gc/sinit.c @@ -286,8 +286,8 @@ staticcopy(Node *l, Node *r, NodeList **out) if(r->op != ONAME || r->class != PEXTERN || r->sym->pkg != localpkg) return 0; - if(r->defn == N) // zeroed - return 1; + if(r->defn == N) // probably zeroed but perhaps supplied externally and of unknown value + return 0; if(r->defn->op != OAS) return 0; orig = r; @@ -354,11 +354,13 @@ staticcopy(Node *l, Node *r, NodeList **out) else { ll = nod(OXXX, N, N); *ll = n1; + ll->orig = ll; // completely separate copy if(!staticassign(ll, e->expr, out)) { // Requires computation, but we're // copying someone else's computation. rr = nod(OXXX, N, N); *rr = *orig; + rr->orig = rr; // completely separate copy rr->type = ll->type; rr->xoffset += e->xoffset; *out = list(*out, nod(OAS, ll, rr)); @@ -378,6 +380,7 @@ staticassign(Node *l, Node *r, NodeList **out) InitPlan *p; InitEntry *e; int i; + Strlit *sval; switch(r->op) { default: @@ -426,6 +429,14 @@ staticassign(Node *l, Node *r, NodeList **out) } break; + case OSTRARRAYBYTE: + if(l->class == PEXTERN && r->left->op == OLITERAL) { + sval = r->left->val.u.sval; + slicebytes(l, sval->s, sval->len); + return 1; + } + break; + case OARRAYLIT: initplan(r); if(isslice(r->type)) { @@ -459,6 +470,7 @@ staticassign(Node *l, Node *r, NodeList **out) else { a = nod(OXXX, N, N); *a = n1; + a->orig = a; // completely separate copy if(!staticassign(a, e->expr, out)) *out = list(*out, nod(OAS, a, e->expr)); } @@ -756,11 +768,24 @@ slicelit(int ctxt, Node *n, Node *var, NodeList **init) vauto = temp(ptrto(t)); // set auto to point at new temp or heap (3 assign) - if(n->esc == EscNone) { - a = nod(OAS, temp(t), N); - typecheck(&a, Etop); - *init = list(*init, a); // zero new temp - a = nod(OADDR, a->left, N); + if(n->alloc != N) { + // temp allocated during order.c for dddarg + n->alloc->type = t; + if(vstat == N) { + a = nod(OAS, n->alloc, N); + typecheck(&a, Etop); + *init = list(*init, a); // zero new temp + } + a = nod(OADDR, n->alloc, N); + } else if(n->esc == EscNone) { + a = temp(t); + if(vstat == N) { + a = nod(OAS, temp(t), N); + typecheck(&a, Etop); + *init = list(*init, a); // zero new temp + a = a->left; + } + a = nod(OADDR, a, N); } else { a = nod(ONEW, N, N); a->list = list1(typenod(t)); @@ -827,7 +852,7 @@ maplit(int ctxt, Node *n, Node *var, NodeList **init) int nerr; int64 b; Type *t, *tk, *tv, *t1; - Node *vstat, *index, *value; + Node *vstat, *index, *value, *key, *val; Sym *syma, *symb; USED(ctxt); @@ -846,7 +871,7 @@ ctxt = 0; r = l->n; if(r->op != OKEY) - fatal("slicelit: rhs not OKEY: %N", r); + fatal("maplit: rhs not OKEY: %N", r); index = r->left; value = r->right; @@ -890,7 +915,7 @@ ctxt = 0; r = l->n; if(r->op != OKEY) - fatal("slicelit: rhs not OKEY: %N", r); + fatal("maplit: rhs not OKEY: %N", r); index = r->left; value = r->right; @@ -941,8 +966,7 @@ ctxt = 0; a->ninit = list1(nod(OAS, index, nodintconst(0))); a->ntest = nod(OLT, index, nodintconst(t->bound)); - a->nincr = nod(OASOP, index, nodintconst(1)); - a->nincr->etype = OADD; + a->nincr = nod(OAS, index, nod(OADD, index, nodintconst(1))); typecheck(&a, Etop); walkstmt(&a); @@ -950,25 +974,49 @@ ctxt = 0; } // put in dynamic entries one-at-a-time + key = nil; + val = nil; for(l=n->list; l; l=l->next) { r = l->n; if(r->op != OKEY) - fatal("slicelit: rhs not OKEY: %N", r); + fatal("maplit: rhs not OKEY: %N", r); index = r->left; value = r->right; if(isliteral(index) && isliteral(value)) continue; + + // build list of var[c] = expr. + // use temporary so that mapassign1 can have addressable key, val. + if(key == nil) { + key = temp(var->type->down); + val = temp(var->type->type); + } + a = nod(OAS, key, r->left); + typecheck(&a, Etop); + walkstmt(&a); + *init = list(*init, a); + a = nod(OAS, val, r->right); + typecheck(&a, Etop); + walkstmt(&a); + *init = list(*init, a); - // build list of var[c] = expr - a = nod(OINDEX, var, r->left); - a = nod(OAS, a, r->right); + a = nod(OAS, nod(OINDEX, var, key), val); typecheck(&a, Etop); - walkexpr(&a, init); + walkstmt(&a); + *init = list(*init, a); + if(nerr != nerrors) break; - + } + + if(key != nil) { + a = nod(OVARKILL, key, N); + typecheck(&a, Etop); + *init = list(*init, a); + a = nod(OVARKILL, val, N); + typecheck(&a, Etop); *init = list(*init, a); } } @@ -988,12 +1036,16 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init) if(!isptr[t->etype]) fatal("anylit: not ptr"); - r = nod(ONEW, N, N); - r->typecheck = 1; - r->type = t; - r->esc = n->esc; + if(n->right != N) { + r = nod(OADDR, n->right, N); + typecheck(&r, Erv); + } else { + r = nod(ONEW, N, N); + r->typecheck = 1; + r->type = t; + r->esc = n->esc; + } walkexpr(&r, init); - a = nod(OAS, var, r); typecheck(&a, Etop); diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c index bea90b87b..72a9ac20c 100644 --- a/src/cmd/gc/subr.c +++ b/src/cmd/gc/subr.c @@ -88,6 +88,7 @@ flusherrors(void) { int i; + Bflush(&bstdout); if(nerr == 0) return; qsort(err, nerr, sizeof err[0], errcmp); @@ -258,9 +259,6 @@ fatal(char *fmt, ...) void linehist(char *file, int32 off, int relative) { - Hist *h; - char *cp; - if(debug['i']) { if(file != nil) { if(off < 0) @@ -274,25 +272,10 @@ linehist(char *file, int32 off, int relative) print("end of import"); print(" at line %L\n", lexlineno); } - - if(off < 0 && file[0] != '/' && !relative) { - cp = mal(strlen(file) + strlen(pathname) + 2); - sprint(cp, "%s/%s", pathname, file); - file = cp; - } - - h = mal(sizeof(Hist)); - h->name = file; - h->line = lexlineno; - h->offset = off; - h->link = H; - if(ehist == H) { - hist = h; - ehist = h; - return; - } - ehist->link = h; - ehist = h; + + if(off < 0 && file[0] != '/' && !relative) + file = smprint("%s/%s", ctxt->pathname, file); + linklinehist(ctxt, lexlineno, file, off); } int32 @@ -607,8 +590,6 @@ algtype1(Type *t, Type **bad) *bad = t; return ANOEQ; } - if(t->bound == 0) - return AMEM; a = algtype1(t->type, bad); if(a == ANOEQ || a == AMEM) { if(a == ANOEQ && bad) @@ -1242,8 +1223,10 @@ assignop(Type *src, Type *dst, char **why) // 2. src and dst have identical underlying types // and either src or dst is not a named type or - // both are interface types. - if(eqtype(src->orig, dst->orig) && (src->sym == S || dst->sym == S || src->etype == TINTER)) + // both are empty interface types. + // For assignable but different non-empty interface types, + // we want to recompute the itab. + if(eqtype(src->orig, dst->orig) && (src->sym == S || dst->sym == S || isnilinter(src))) return OCONVNOP; // 3. dst is an interface type and src implements dst. @@ -1251,13 +1234,16 @@ assignop(Type *src, Type *dst, char **why) if(implements(src, dst, &missing, &have, &ptr)) return OCONVIFACE; - // we'll have complained about this method anyway, supress spurious messages. + // we'll have complained about this method anyway, suppress spurious messages. if(have && have->sym == missing->sym && (have->type->broke || missing->type->broke)) return OCONVIFACE; if(why != nil) { if(isptrto(src, TINTER)) *why = smprint(":\n\t%T is pointer to interface, not interface", src); + else if(have && have->sym == missing->sym && have->nointerface) + *why = smprint(":\n\t%T does not implement %T (%S method is marked 'nointerface')", + src, dst, missing->sym); else if(have && have->sym == missing->sym) *why = smprint(":\n\t%T does not implement %T (wrong type for %S method)\n" "\t\thave %S%hhT\n\t\twant %S%hhT", src, dst, missing->sym, @@ -1692,7 +1678,7 @@ typehash(Type *t) md5reset(&d); md5write(&d, (uchar*)p, strlen(p)); free(p); - return md5sum(&d); + return md5sum(&d, nil); } Type* @@ -2115,7 +2101,7 @@ cheapexpr(Node *n, NodeList **init) Node* localexpr(Node *n, Type *t, NodeList **init) { - if(n->op == ONAME && !n->addrtaken && + if(n->op == ONAME && (!n->addrtaken || strncmp(n->sym->name, "autotmp_", 8) == 0) && (n->class == PAUTO || n->class == PPARAM || n->class == PPARAMOUT) && convertop(n->type, t, nil) == OCONVNOP) return n; @@ -2257,6 +2243,7 @@ adddot(Node *n) int c, d; typecheck(&n->left, Etype|Erv); + n->diag |= n->left->diag; t = n->left->type; if(t == T) goto ret; @@ -2506,12 +2493,19 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface) Type *tpad, *methodrcvr; int isddd; Val v; + static int linehistdone = 0; if(0 && debug['r']) print("genwrapper rcvrtype=%T method=%T newnam=%S\n", rcvr, method, newnam); - lineno = 1; // less confusing than end of input + lexlineno++; + lineno = lexlineno; + if (linehistdone == 0) { + // All the wrappers can share the same linehist entry. + linehist("", 0, 0); + linehistdone = 1; + } dclcontext = PEXTERN; markdcl(); @@ -2608,8 +2602,10 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface) funcbody(fn); curfn = fn; - // wrappers where T is anonymous (struct{ NamedType }) can be duplicated. - if(rcvr->etype == TSTRUCT || isptr[rcvr->etype] && rcvr->type->etype == TSTRUCT) + // wrappers where T is anonymous (struct or interface) can be duplicated. + if(rcvr->etype == TSTRUCT || + rcvr->etype == TINTER || + isptr[rcvr->etype] && rcvr->type->etype == TSTRUCT) fn->dupok = 1; typecheck(&fn, Etop); typechecklist(fn->nbody, Etop); @@ -3631,7 +3627,8 @@ ngotype(Node *n) * only in the last segment of the path, and it makes for happier * users if we escape that as little as possible. * - * If you edit this, edit ../ld/lib.c:/^pathtoprefix copy too. + * If you edit this, edit ../ld/lib.c:/^pathtoprefix too. + * If you edit this, edit ../../pkg/debug/goobj/read.go:/importPathToPrefix too. */ static char* pathtoprefix(char *s) diff --git a/src/cmd/gc/swt.c b/src/cmd/gc/swt.c index d6aa021a9..ce0190507 100644 --- a/src/cmd/gc/swt.c +++ b/src/cmd/gc/swt.c @@ -317,7 +317,7 @@ casebody(Node *sw, Node *typeswvar) // botch - shouldn't fall thru declaration last = stat->end->n; - if(last->op == OXFALL) { + if(last->xoffset == n->xoffset && last->op == OXFALL) { if(typeswvar) { setlineno(last); yyerror("cannot fallthrough in type switch"); diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c index 31a2f2c5c..c50b2285b 100644 --- a/src/cmd/gc/typecheck.c +++ b/src/cmd/gc/typecheck.c @@ -310,7 +310,7 @@ typecheck1(Node **np, int top) int ok, ntop; Type *t, *tp, *missing, *have, *badtype; Val v; - char *why; + char *why, *desc, descbuf[64]; n = *np; @@ -368,7 +368,7 @@ reswitch: goto ret; case OPACK: - yyerror("use of package %S not in selector", n->sym); + yyerror("use of package %S without selector", n->sym); goto error; case ODDD: @@ -535,6 +535,19 @@ reswitch: op = n->etype; goto arith; + case OADDPTR: + ok |= Erv; + l = typecheck(&n->left, Erv); + r = typecheck(&n->right, Erv); + if(l->type == T || r->type == T) + goto error; + if(l->type->etype != tptr) + fatal("bad OADDPTR left type %E for %N", l->type->etype, n->left); + if(r->type->etype != TUINTPTR) + fatal("bad OADDPTR right type %E for %N", r->type->etype, n->right); + n->type = types[tptr]; + goto ret; + case OADD: case OAND: case OANDAND: @@ -654,8 +667,20 @@ reswitch: if(iscmp[n->op]) { n->etype = n->op; n->op = OCMPSTR; - } else if(n->op == OADD) + } else if(n->op == OADD) { + // create OADDSTR node with list of strings in x + y + z + (w + v) + ... n->op = OADDSTR; + if(l->op == OADDSTR) + n->list = l->list; + else + n->list = list1(l); + if(r->op == OADDSTR) + n->list = concat(n->list, r->list); + else + n->list = list(n->list, r); + n->left = N; + n->right = N; + } } if(et == TINTER) { if(l->op == OLITERAL && l->val.ctype == CTNIL) { @@ -721,8 +746,11 @@ reswitch: if(n->left->type == T) goto error; checklvalue(n->left, "take the address of"); - for(l=n->left; l->op == ODOT; l=l->left) + r = outervalue(n->left); + for(l = n->left; l != r; l = l->left) l->addrtaken = 1; + if(l->orig != l && l->op == ONAME) + fatal("found non-orig name node %N", l); l->addrtaken = 1; defaultlit(&n->left, T); l = n->left; @@ -864,7 +892,7 @@ reswitch: goto error; switch(t->etype) { default: - yyerror("invalid operation: %N (index of type %T)", n, t); + yyerror("invalid operation: %N (type %T does not support indexing)", n, t); goto error; @@ -947,7 +975,7 @@ reswitch: r = n->right; if(r->type == T) goto error; - r = assignconv(r, l->type->type, "send"); + n->right = assignconv(r, l->type->type, "send"); // TODO: more aggressive n->etype = 0; n->type = T; @@ -1062,6 +1090,7 @@ reswitch: goto reswitch; } typecheck(&n->left, Erv | Etype | Ecall |(top&Eproc)); + n->diag |= n->left->diag; l = n->left; if(l->op == ONAME && l->etype != 0) { if(n->isddd && l->etype != OAPPEND) @@ -1123,7 +1152,11 @@ reswitch: } break; } - typecheckaste(OCALL, n->left, n->isddd, getinargx(t), n->list, "function argument"); + if(snprint(descbuf, sizeof descbuf, "argument to %N", n->left) < sizeof descbuf) + desc = descbuf; + else + desc = "function argument"; + typecheckaste(OCALL, n->left, n->isddd, getinargx(t), n->list, desc); ok |= Etop; if(t->outtuple == 0) goto ret; @@ -1209,17 +1242,29 @@ reswitch: case OCOMPLEX: ok |= Erv; - if(twoarg(n) < 0) - goto error; - l = typecheck(&n->left, Erv | (top & Eiota)); - r = typecheck(&n->right, Erv | (top & Eiota)); - if(l->type == T || r->type == T) - goto error; - defaultlit2(&l, &r, 0); - if(l->type == T || r->type == T) - goto error; - n->left = l; - n->right = r; + if(count(n->list) == 1) { + typechecklist(n->list, Efnstruct); + t = n->list->n->left->type; + if(t->outtuple != 2) { + yyerror("invalid operation: complex expects two arguments, %N returns %d results", n->list->n, t->outtuple); + goto error; + } + t = n->list->n->type->type; + l = t->nname; + r = t->down->nname; + } else { + if(twoarg(n) < 0) + goto error; + l = typecheck(&n->left, Erv | (top & Eiota)); + r = typecheck(&n->right, Erv | (top & Eiota)); + if(l->type == T || r->type == T) + goto error; + defaultlit2(&l, &r, 0); + if(l->type == T || r->type == T) + goto error; + n->left = l; + n->right = r; + } if(!eqtype(l->type, r->type)) { yyerror("invalid operation: %N (mismatched types %T and %T)", n, l->type, r->type); goto error; @@ -1298,9 +1343,22 @@ reswitch: yyerror("missing arguments to append"); goto error; } - typechecklist(args, Erv); + + if(count(args) == 1 && !n->isddd) + typecheck(&args->n, Erv | Efnstruct); + else + typechecklist(args, Erv); + if((t = args->n->type) == T) goto error; + + // Unpack multiple-return result before type-checking. + if(istype(t, TSTRUCT)) { + t = t->type; + if(istype(t, TFIELD)) + t = t->type; + } + n->type = t; if(!isslice(t)) { if(isconst(args->n, CTNIL)) { @@ -1355,6 +1413,8 @@ reswitch: goto error; defaultlit(&n->left, T); defaultlit(&n->right, T); + if(n->left->type == T || n->right->type == T) + goto error; // copy([]byte, string) if(isslice(n->left->type) && n->right->type->etype == TSTRING) { @@ -1406,6 +1466,9 @@ reswitch: } break; case OSTRARRAYBYTE: + // do not use stringtoarraylit. + // generated code and compiler memory footprint is better without it. + break; case OSTRARRAYRUNE: if(n->left->op == OLITERAL) stringtoarraylit(&n); @@ -1621,6 +1684,7 @@ reswitch: case OGOTO: case OLABEL: case OXFALL: + case OVARKILL: ok |= Etop; goto ret; @@ -2116,6 +2180,31 @@ nokeys(NodeList *l) return 1; } +static int +hasddd(Type *t) +{ + Type *tl; + + for(tl=t->type; tl; tl=tl->down) { + if(tl->isddd) + return 1; + } + return 0; +} + +static int +downcount(Type *t) +{ + Type *tl; + int n; + + n = 0; + for(tl=t->type; tl; tl=tl->down) { + n++; + } + return n; +} + /* * typecheck assignment: type list = expression list */ @@ -2126,14 +2215,25 @@ typecheckaste(int op, Node *call, int isddd, Type *tstruct, NodeList *nl, char * Node *n; int lno; char *why; + int n1, n2; lno = lineno; if(tstruct->broke) goto out; + n = N; if(nl != nil && nl->next == nil && (n = nl->n)->type != T) if(n->type->etype == TSTRUCT && n->type->funarg) { + if(!hasddd(tstruct)) { + n1 = downcount(tstruct); + n2 = downcount(n->type); + if(n2 > n1) + goto toomany; + if(n2 < n1) + goto notenough; + } + tn = n->type->type; for(tl=tstruct->type; tl; tl=tl->down) { if(tl->isddd) { @@ -2162,6 +2262,26 @@ typecheckaste(int op, Node *call, int isddd, Type *tstruct, NodeList *nl, char * goto out; } + n1 = downcount(tstruct); + n2 = count(nl); + if(!hasddd(tstruct)) { + if(n2 > n1) + goto toomany; + if(n2 < n1) + goto notenough; + } + else { + if(!isddd) { + if(n2 < n1-1) + goto notenough; + } else { + if(n2 > n1) + goto toomany; + if(n2 < n1) + goto notenough; + } + } + for(tl=tstruct->type; tl; tl=tl->down) { t = tl->type; if(tl->isddd) { @@ -2206,10 +2326,14 @@ out: return; notenough: - if(call != N) - yyerror("not enough arguments in call to %N", call); - else - yyerror("not enough arguments to %O", op); + if(n == N || !n->diag) { + if(call != N) + yyerror("not enough arguments in call to %N", call); + else + yyerror("not enough arguments to %O", op); + if(n != N) + n->diag = 1; + } goto out; toomany: @@ -2252,10 +2376,13 @@ keydup(Node *n, Node *hash[], ulong nhash) ulong b; double d; int i; - Node *a; + Node *a, *orign; Node cmp; char *s; + orign = n; + if(n->op == OCONVIFACE) + n = n->left; evconst(n); if(n->op != OLITERAL) return; // we dont check variables @@ -2288,17 +2415,25 @@ keydup(Node *n, Node *hash[], ulong nhash) for(a=hash[h]; a!=N; a=a->ntest) { cmp.op = OEQ; cmp.left = n; - cmp.right = a; - evconst(&cmp); - b = cmp.val.u.bval; + b = 0; + if(a->op == OCONVIFACE && orign->op == OCONVIFACE) { + if(eqtype(a->left->type, n->type)) { + cmp.right = a->left; + evconst(&cmp); + b = cmp.val.u.bval; + } + } else if(eqtype(a->type, n->type)) { + cmp.right = a; + evconst(&cmp); + b = cmp.val.u.bval; + } if(b) { - // too lazy to print the literal yyerror("duplicate key %N in map literal", n); return; } } - n->ntest = hash[h]; - hash[h] = n; + orign->ntest = hash[h]; + hash[h] = orign; } static void @@ -2486,8 +2621,9 @@ typecheckcomplit(Node **np) typecheck(&l->left, Erv); evconst(l->left); i = nonnegconst(l->left); - if(i < 0) { + if(i < 0 && !l->left->diag) { yyerror("array index must be non-negative integer constant"); + l->left->diag = 1; i = -(1<<30); // stay negative for a while } if(i >= 0) @@ -2497,7 +2633,7 @@ typecheckcomplit(Node **np) len = i; if(t->bound >= 0 && len > t->bound) { setlineno(l); - yyerror("array index %d out of bounds [0:%d]", len, t->bound); + yyerror("array index %lld out of bounds [0:%lld]", len-1, t->bound); t->bound = -1; // no more errors } } @@ -2680,6 +2816,11 @@ checkassign(Node *n) n->etype = 1; return; } + + // have already complained about n being undefined + if(n->op == ONONAME) + return; + yyerror("cannot assign to %N", n); } @@ -2804,7 +2945,7 @@ typecheckas2(Node *n) n->op = OAS2FUNC; t = structfirst(&s, &r->type); for(ll=n->list; ll; ll=ll->next) { - if(ll->n->type != T) + if(t->type != T && ll->n->type != T) checkassignto(t->type, ll->n); if(ll->n->defn == n && ll->n->ntype == N) ll->n->type = t->type; @@ -3130,7 +3271,10 @@ typecheckdef(Node *n) goto ret; } if(e->type != T && e->op != OLITERAL || !isgoconst(e)) { - yyerror("const initializer %N is not a constant", e); + if(!e->diag) { + yyerror("const initializer %N is not a constant", e); + e->diag = 1; + } goto ret; } t = n->type; @@ -3220,29 +3364,38 @@ static int checkmake(Type *t, char *arg, Node *n) { if(n->op == OLITERAL) { - n->val = toint(n->val); - if(mpcmpfixc(n->val.u.xval, 0) < 0) { - yyerror("negative %s argument in make(%T)", arg, t); - return -1; - } - if(mpcmpfixfix(n->val.u.xval, maxintval[TINT]) > 0) { - yyerror("%s argument too large in make(%T)", arg, t); - return -1; + switch(n->val.ctype) { + case CTINT: + case CTRUNE: + case CTFLT: + case CTCPLX: + n->val = toint(n->val); + if(mpcmpfixc(n->val.u.xval, 0) < 0) { + yyerror("negative %s argument in make(%T)", arg, t); + return -1; + } + if(mpcmpfixfix(n->val.u.xval, maxintval[TINT]) > 0) { + yyerror("%s argument too large in make(%T)", arg, t); + return -1; + } + + // Delay defaultlit until after we've checked range, to avoid + // a redundant "constant NNN overflows int" error. + defaultlit(&n, types[TINT]); + return 0; + default: + break; } - - // Delay defaultlit until after we've checked range, to avoid - // a redundant "constant NNN overflows int" error. - defaultlit(&n, types[TINT]); - return 0; } - - // Defaultlit still necessary for non-constant: n might be 1<type->etype]) { + if(!isint[n->type->etype] && n->type->etype != TIDEAL) { yyerror("non-integer %s argument in make(%T) - %T", arg, t, n->type); return -1; } + + // Defaultlit still necessary for non-constant: n might be 1<op = OEMPTY; // don't leave plain values as statements. break; + case ORECV: + // special case for a receive where we throw away + // the value received. + if(n->typecheck == 0) + fatal("missing typecheck: %+N", n); + init = n->ninit; + n->ninit = nil; + + walkexpr(&n->left, &init); + n = mkcall1(chanfn("chanrecv1", 2, n->left->type), T, &init, typename(n->left->type), n->left, nodnil()); + walkexpr(&n, &init); + + addinit(&n, init); + break; + case OBREAK: case ODCL: case OCONTINUE: @@ -188,6 +202,7 @@ walkstmt(Node **np) case ODCLCONST: case ODCLTYPE: case OCHECKNIL: + case OVARKILL: break; case OBLOCK: @@ -209,6 +224,9 @@ walkstmt(Node **np) walkexprlist(n->left->list, &n->ninit); n->left = walkprint(n->left, &n->ninit, 1); break; + case OCOPY: + n->left = copyany(n->left, &n->ninit, 1); + break; default: walkexpr(&n->left, &n->ninit); break; @@ -240,6 +258,9 @@ walkstmt(Node **np) walkexprlist(n->left->list, &n->ninit); n->left = walkprint(n->left, &n->ninit, 1); break; + case OCOPY: + n->left = copyany(n->left, &n->ninit, 1); + break; default: walkexpr(&n->left, &n->ninit); break; @@ -341,7 +362,8 @@ void walkexpr(Node **np, NodeList **init) { Node *r, *l, *var, *a; - NodeList *ll, *lr, *lpost; + Node *map, *key; + NodeList *ll, *lr; Type *t; int et, old_safemode; int64 v; @@ -455,7 +477,6 @@ walkexpr(Node **np, NodeList **init) case ORSH: walkexpr(&n->left, init); walkexpr(&n->right, init); - shiftwalked: t = n->left->type; n->bounded = bounded(n->right, 8*t->width); if(debug['m'] && n->etype && !isconst(n->right, CTINT)) @@ -472,6 +493,11 @@ walkexpr(Node **np, NodeList **init) case OADD: case OCOMPLEX: case OLROT: + // Use results from call expression as arguments for complex. + if(n->op == OCOMPLEX && n->left == N && n->right == N) { + n->left = n->list->n; + n->right = n->list->next->n; + } walkexpr(&n->left, init); walkexpr(&n->right, init); goto ret; @@ -576,13 +602,32 @@ walkexpr(Node **np, NodeList **init) case OAS: *init = concat(*init, n->ninit); n->ninit = nil; + walkexpr(&n->left, init); n->left = safeexpr(n->left, init); if(oaslit(n, init)) goto ret; - walkexpr(&n->right, init); + if(n->right == N) + goto ret; + + switch(n->right->op) { + default: + walkexpr(&n->right, init); + break; + + case ORECV: + // x = <-c; n->left is x, n->right->left is c. + // orderstmt made sure x is addressable. + walkexpr(&n->right->left, init); + n1 = nod(OADDR, n->left, N); + r = n->right->left; // the channel + n = mkcall1(chanfn("chanrecv1", 2, r->type), T, init, typename(r->type), r, n1); + walkexpr(&n, init); + goto ret; + } + if(n->left != N && n->right != N) { r = convas(nod(OAS, n->left, n->right), init); r->dodata = n->dodata; @@ -602,53 +647,35 @@ walkexpr(Node **np, NodeList **init) goto ret; case OAS2FUNC: - as2func: // a,b,... = fn() *init = concat(*init, n->ninit); n->ninit = nil; r = n->rlist->n; walkexprlistsafe(n->list, init); walkexpr(&r, init); - l = n->list->n; - - // all the really hard stuff - explicit function calls and so on - - // is gone, but map assignments remain. - // if there are map assignments here, assign via - // temporaries, because ascompatet assumes - // the targets can be addressed without function calls - // and map index has an implicit one. - lpost = nil; - if(l->op == OINDEXMAP) { - var = temp(l->type); - n->list->n = var; - a = nod(OAS, l, var); - typecheck(&a, Etop); - lpost = list(lpost, a); - } - l = n->list->next->n; - if(l->op == OINDEXMAP) { - var = temp(l->type); - n->list->next->n = var; - a = nod(OAS, l, var); - typecheck(&a, Etop); - lpost = list(lpost, a); - } + ll = ascompatet(n->op, n->list, &r->type, 0, init); - walkexprlist(lpost, init); - n = liststmt(concat(concat(list1(r), ll), lpost)); + n = liststmt(concat(list1(r), ll)); goto ret; case OAS2RECV: + // x, y = <-c + // orderstmt made sure x is addressable. *init = concat(*init, n->ninit); n->ninit = nil; r = n->rlist->n; walkexprlistsafe(n->list, init); walkexpr(&r->left, init); + if(isblank(n->list->n)) + n1 = nodnil(); + else + n1 = nod(OADDR, n->list->n, N); + n1->etype = 1; // addr does not escape fn = chanfn("chanrecv2", 2, r->left->type); - r = mkcall1(fn, getoutargx(fn->type), init, typename(r->left->type), r->left); - n->rlist->n = r; - n->op = OAS2FUNC; - goto as2func; + r = mkcall1(fn, types[TBOOL], init, typename(r->left->type), r->left, n1); + n = nod(OAS, n->list->next->n, r); + typecheck(&n, Etop); + goto ret; case OAS2MAPR: // a,b = m[i]; @@ -657,6 +684,7 @@ walkexpr(Node **np, NodeList **init) r = n->rlist->n; walkexprlistsafe(n->list, init); walkexpr(&r->left, init); + walkexpr(&r->right, init); t = r->left->type; p = nil; if(t->type->width <= 128) { // Check ../../pkg/runtime/hashmap.c:MAXVALUESIZE before changing. @@ -675,41 +703,50 @@ walkexpr(Node **np, NodeList **init) } } if(p != nil) { - // from: - // a,b = m[i] - // to: - // var,b = mapaccess2_fast*(t, m, i) - // a = *var - a = n->list->n; - var = temp(ptrto(t->type)); - var->typecheck = 1; - - fn = mapfn(p, t); - r = mkcall1(fn, getoutargx(fn->type), init, typename(t), r->left, r->right); - n->rlist = list1(r); - n->op = OAS2FUNC; - n->list->n = var; - walkexpr(&n, init); - *init = list(*init, n); - - n = nod(OAS, a, nod(OIND, var, N)); - typecheck(&n, Etop); - walkexpr(&n, init); - goto ret; - } - fn = mapfn("mapaccess2", t); - r = mkcall1(fn, getoutargx(fn->type), init, typename(t), r->left, r->right); + // fast versions take key by value + key = r->right; + } else { + // standard version takes key by reference + // orderexpr made sure key is addressable. + key = nod(OADDR, r->right, N); + p = "mapaccess2"; + } + + // from: + // a,b = m[i] + // to: + // var,b = mapaccess2*(t, m, i) + // a = *var + a = n->list->n; + var = temp(ptrto(t->type)); + var->typecheck = 1; + fn = mapfn(p, t); + r = mkcall1(fn, getoutargx(fn->type), init, typename(t), r->left, key); n->rlist = list1(r); n->op = OAS2FUNC; - goto as2func; + n->list->n = var; + walkexpr(&n, init); + *init = list(*init, n); + n = nod(OAS, a, nod(OIND, var, N)); + typecheck(&n, Etop); + walkexpr(&n, init); + // mapaccess needs a zero value to be at least this big. + if(zerosize < t->type->width) + zerosize = t->type->width; + // TODO: ptr is always non-nil, so disable nil check for this OIND op. + goto ret; case ODELETE: *init = concat(*init, n->ninit); n->ninit = nil; - l = n->list->n; - r = n->list->next->n; - t = l->type; - n = mkcall1(mapfndel("mapdelete", t), t->down, init, typename(t), l, r); + map = n->list->n; + key = n->list->next->n; + walkexpr(&map, init); + walkexpr(&key, init); + // orderstmt made sure key is addressable. + key = nod(OADDR, key, N); + t = map->type; + n = mkcall1(mapfndel("mapdelete", t), T, init, typename(t), map, key); goto ret; case OAS2DOTTYPE: @@ -872,7 +909,20 @@ walkexpr(Node **np, NodeList **init) goto ret; } } - ll = list(ll, n->left); + if(isinter(n->left->type)) { + ll = list(ll, n->left); + } else { + // regular types are passed by reference to avoid C vararg calls + // orderexpr arranged for n->left to be a temporary for all + // the conversions it could see. comparison of an interface + // with a non-interface, especially in a switch on interface value + // with non-interface cases, is not visible to orderstmt, so we + // have to fall back on allocating a temp here. + if(islvalue(n->left)) + ll = list(ll, nod(OADDR, n->left, N)); + else + ll = list(ll, nod(OADDR, copyexpr(n->left, n->left->type, init), N)); + } argtype(fn, n->left->type); argtype(fn, n->type); dowidth(fn->type); @@ -909,51 +959,6 @@ walkexpr(Node **np, NodeList **init) walkexpr(&n->left, init); goto ret; - case OASOP: - 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 integer/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 || - (!isfloat[et] && n->etype == ODIV) || - n->etype == OMOD) { - l = safeexpr(n->left, init); - a = l; - if(a->op == OINDEXMAP) { - // map index has "lhs" bit set in a->etype. - // make a copy so we can clear it on the rhs. - a = nod(OXXX, N, N); - *a = *l; - a->etype = 0; - } - r = nod(OAS, l, nod(n->etype, a, n->right)); - typecheck(&r, Etop); - walkexpr(&r, init); - n = r; - goto ret; - } - if(n->etype == OLSH || n->etype == ORSH) - goto shiftwalked; - goto ret; - case OANDNOT: walkexpr(&n->left, init); n->op = OAND; @@ -998,7 +1003,7 @@ walkexpr(Node **np, NodeList **init) switch(n->op) { case OMOD: case ODIV: - if(widthptr > 4 || (et != TUINT64 && et != TINT64)) + if(widthreg >= 8 || (et != TUINT64 && et != TINT64)) goto ret; if(et == TINT64) strcpy(namebuf, "int64"); @@ -1063,6 +1068,8 @@ walkexpr(Node **np, NodeList **init) case OINDEXMAP: if(n->etype == 1) goto ret; + walkexpr(&n->left, init); + walkexpr(&n->right, init); t = n->left->type; p = nil; @@ -1082,23 +1089,25 @@ walkexpr(Node **np, NodeList **init) } } if(p != nil) { - // use fast version. The fast versions return a pointer to the value - we need - // to dereference it to get the result. - n = mkcall1(mapfn(p, t), ptrto(t->type), init, typename(t), n->left, n->right); - n = nod(OIND, n, N); - n->type = t->type; - n->typecheck = 1; + // fast versions take key by value + key = n->right; } else { - // no fast version for this key - n = mkcall1(mapfn("mapaccess1", t), t->type, init, typename(t), n->left, n->right); - } + // standard version takes key by reference. + // orderexpr made sure key is addressable. + key = nod(OADDR, n->right, N); + p = "mapaccess1"; + } + n = mkcall1(mapfn(p, t), ptrto(t->type), init, typename(t), n->left, key); + n = nod(OIND, n, N); + n->type = t->type; + n->typecheck = 1; + // mapaccess needs a zero value to be at least this big. + if(zerosize < t->type->width) + zerosize = t->type->width; goto ret; case ORECV: - walkexpr(&n->left, init); - walkexpr(&n->right, init); - n = mkcall1(chanfn("chanrecv1", 2, n->left->type), n->type, init, typename(n->left->type), n->left); - goto ret; + fatal("walkexpr ORECV"); // should see inside OAS only case OSLICE: if(n->right != N && n->right->left == N && n->right->right == N) { // noop @@ -1182,9 +1191,10 @@ walkexpr(Node **np, NodeList **init) // s + "badgerbadgerbadger" == "badgerbadgerbadger" if((n->etype == OEQ || n->etype == ONE) && isconst(n->right, CTSTR) && - n->left->op == OADDSTR && isconst(n->left->right, CTSTR) && - cmpslit(n->right, n->left->right) == 0) { - r = nod(n->etype, nod(OLEN, n->left->left, N), nodintconst(0)); + n->left->op == OADDSTR && count(n->left->list) == 2 && + isconst(n->left->list->next->n, CTSTR) && + cmpslit(n->right, n->left->list->next->n) == 0) { + r = nod(n->etype, nod(OLEN, n->left->list->n, N), nodintconst(0)); typecheck(&r, Erv); walkexpr(&r, init); r->type = n->type; @@ -1238,19 +1248,7 @@ walkexpr(Node **np, NodeList **init) goto ret; case OCOPY: - if(flag_race) { - if(n->right->type->etype == TSTRING) - fn = syslook("slicestringcopy", 1); - else - fn = syslook("copy", 1); - argtype(fn, n->left->type); - argtype(fn, n->right->type); - n = mkcall1(fn, n->type, init, - n->left, n->right, - nodintconst(n->left->type->type->width)); - goto ret; - } - n = copyany(n, init); + n = copyany(n, init, flag_race); goto ret; case OCLOSE: @@ -1321,6 +1319,11 @@ walkexpr(Node **np, NodeList **init) n = mkcall("slicebytetostring", n->type, init, n->left); goto ret; + case OARRAYBYTESTRTMP: + // slicebytetostringtmp([]byte) string; + n = mkcall("slicebytetostringtmp", n->type, init, n->left); + goto ret; + case OARRAYRUNESTR: // slicerunetostring([]rune) string; n = mkcall("slicerunetostring", n->type, init, n->left); @@ -1368,13 +1371,18 @@ walkexpr(Node **np, NodeList **init) case OMAPLIT: case OSTRUCTLIT: case OPTRLIT: + // XXX TODO do we need to clear var? var = temp(n->type); anylit(0, n, var, init); n = var; goto ret; case OSEND: - n = mkcall1(chanfn("chansend1", 2, n->left->type), T, init, typename(n->left->type), n->left, n->right); + n1 = n->right; + n1 = assignconv(n1, n->left->type->type, "chan send"); + walkexpr(&n1, init); + n1 = nod(OADDR, n1, N); + n = mkcall1(chanfn("chansend1", 2, n->left->type), T, init, typename(n->left->type), n->left, n1); goto ret; case OCLOSURE: @@ -1534,11 +1542,16 @@ ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init) * package all the arguments that match a ... T parameter into a []T. */ static NodeList* -mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init, int esc) +mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init, Node *ddd) { Node *a, *n; Type *tslice; - + int esc; + + esc = EscUnknown; + if(ddd != nil) + esc = ddd->esc; + tslice = typ(TARRAY); tslice->type = l->type->type; tslice->bound = -1; @@ -1548,6 +1561,8 @@ mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init, int n->type = tslice; } else { n = nod(OCOMPLIT, N, typenod(tslice)); + if(ddd != nil) + n->alloc = ddd->alloc; // temporary to use n->list = lr0; n->esc = esc; typecheck(&n, Erv); @@ -1619,7 +1634,6 @@ dumpnodetypes(NodeList *l, char *what) static NodeList* ascompatte(int op, Node *call, int isddd, Type **nl, NodeList *lr, int fp, NodeList **init) { - int esc; Type *l, *ll; Node *r, *a; NodeList *nn, *lr0, *alist; @@ -1638,7 +1652,8 @@ ascompatte(int op, Node *call, int isddd, Type **nl, NodeList *lr, int fp, NodeL // optimization - can do block copy if(eqtypenoname(r->type, *nl)) { a = nodarg(*nl, fp); - a->type = r->type; + r = nod(OCONVNOP, r, N); + r->type = a->type; nn = list1(convas(nod(OAS, a, r), init)); goto ret; } @@ -1682,10 +1697,7 @@ loop: // normal case -- make a slice of all // remaining arguments and pass it to // the ddd parameter. - esc = EscUnknown; - if(call->right) - esc = call->right->esc; - nn = mkdotargslice(lr, nn, l, fp, init, esc); + nn = mkdotargslice(lr, nn, l, fp, init, call->right); goto ret; } @@ -1911,6 +1923,7 @@ static Node* convas(Node *n, NodeList **init) { Type *lt, *rt; + Node *map, *key, *val; if(n->op != OAS) fatal("convas: not OAS %O", n->op); @@ -1931,9 +1944,17 @@ convas(Node *n, NodeList **init) } if(n->left->op == OINDEXMAP) { - n = mkcall1(mapfn("mapassign1", n->left->left->type), T, init, - typename(n->left->left->type), - n->left->left, n->left->right, n->right); + map = n->left->left; + key = n->left->right; + val = n->right; + walkexpr(&map, init); + walkexpr(&key, init); + walkexpr(&val, init); + // orderexpr made sure key and val are addressable. + key = nod(OADDR, key, N); + val = nod(OADDR, val, N); + n = mkcall1(mapfn("mapassign1", map->type), T, init, + typename(map->type), map, key, val); goto out; } @@ -2101,7 +2122,7 @@ reorder3save(Node **np, NodeList *all, NodeList *stop, NodeList **early) * what's the outer value that a write to n affects? * outer value means containing struct or array. */ -static Node* +Node* outervalue(Node *n) { for(;;) { @@ -2320,7 +2341,7 @@ paramstoheap(Type **argin, int out) nn = nil; for(t = structfirst(&savet, argin); t != T; t = structnext(&savet)) { v = t->nname; - if(v && v->sym && v->sym->name[0] == '~') + if(v && v->sym && v->sym->name[0] == '~' && v->sym->name[1] == 'r') // unnamed result v = N; // In precisestack mode, the garbage collector assumes results // are always live, so zero them always. @@ -2493,33 +2514,38 @@ mapfndel(char *name, Type *t) 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; intype->list = in; - cat->ntype->rlist = list1(nod(ODCLFIELD, N, typstr)); + Node *r, *cat, *slice; + NodeList *args, *l; + int c; + Type *t; + + // orderexpr rewrote OADDSTR to have a list of strings. + c = count(n->list); + if(c < 2) + yyerror("addstr count %d too small", c); + // build list of string arguments 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); + for(l=n->list; l != nil; l=l->next) + args = list(args, conv(l->n, types[TSTRING])); + if(c <= 5) { + // small numbers of strings use direct runtime helpers. + // note: orderexpr knows this cutoff too. + snprint(namebuf, sizeof(namebuf), "concatstring%d", c); + } else { + // large numbers of strings are passed to the runtime as a slice. + strcpy(namebuf, "concatstrings"); + t = typ(TARRAY); + t->type = types[TSTRING]; + t->bound = -1; + slice = nod(OCOMPLIT, N, typenod(t)); + slice->alloc = n->alloc; + slice->list = args; + slice->esc = EscNone; + args = list1(slice); + } + cat = syslook(namebuf, 1); r = nod(OCALL, cat, N); r->list = args; typecheck(&r, Erv); @@ -2597,9 +2623,10 @@ appendslice(Node *n, NodeList **init) fn = syslook("copy", 1); argtype(fn, l1->type); argtype(fn, l2->type); - l = list(l, mkcall1(fn, types[TINT], init, + nt = mkcall1(fn, types[TINT], &l, nptr1, nptr2, - nodintconst(s->type->type->width))); + nodintconst(s->type->type->width)); + l = list(l, nt); } else { // memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T)) nptr1 = nod(OINDEX, s, nod(OLEN, l1, N)); @@ -2614,7 +2641,8 @@ appendslice(Node *n, NodeList **init) nwid = cheapexpr(conv(nod(OLEN, l2, N), types[TUINTPTR]), &l); nwid = nod(OMUL, nwid, nodintconst(s->type->type->width)); - l = list(l, mkcall1(fn, T, init, nptr1, nptr2, nwid)); + nt = mkcall1(fn, T, &l, nptr1, nptr2, nwid); + l = list(l, nt); } // s = s[:len(l1)+len(l2)] @@ -2660,6 +2688,10 @@ append(Node *n, NodeList **init) l->n = cheapexpr(l->n, init); nsrc = n->list->n; + + // Resolve slice type of multi-valued return. + if(istype(nsrc->type, TSTRUCT)) + nsrc->type = nsrc->type->type->type; argc = count(n->list) - 1; if (argc < 1) { return nsrc; @@ -2705,7 +2737,7 @@ append(Node *n, NodeList **init) return ns; } -// Lower copy(a, b) to a memmove call. +// Lower copy(a, b) to a memmove call or a runtime call. // // init { // n := len(a) @@ -2717,11 +2749,22 @@ append(Node *n, NodeList **init) // Also works if b is a string. // static Node* -copyany(Node *n, NodeList **init) +copyany(Node *n, NodeList **init, int runtimecall) { Node *nl, *nr, *nfrm, *nto, *nif, *nlen, *nwid, *fn; NodeList *l; + if(runtimecall) { + if(n->right->type->etype == TSTRING) + fn = syslook("slicestringcopy", 1); + else + fn = syslook("copy", 1); + argtype(fn, n->left->type); + argtype(fn, n->right->type); + return mkcall1(fn, n->type, init, + n->left, n->right, + nodintconst(n->left->type->type->width)); + } walkexpr(&n->left, init); walkexpr(&n->right, init); nl = temp(n->left->type); @@ -2802,17 +2845,13 @@ sliceany(Node* n, NodeList **init) if(isconst(cb, CTINT)) { cbv = mpgetfix(cb->val.u.xval); - if(cbv < 0 || cbv > bv) { + if(cbv < 0 || cbv > bv) yyerror("slice index out of bounds"); - cbv = -1; - } } if(isconst(hb, CTINT)) { hbv = mpgetfix(hb->val.u.xval); - if(hbv < 0 || hbv > bv) { + if(hbv < 0 || hbv > bv) yyerror("slice index out of bounds"); - hbv = -1; - } } if(isconst(lb, CTINT)) { lbv = mpgetfix(lb->val.u.xval); @@ -3052,13 +3091,10 @@ walkcompare(Node **np, NodeList **init) } if(expr == N) expr = nodbool(n->op == OEQ); - typecheck(&expr, Erv); - walkexpr(&expr, init); - expr->type = n->type; - *np = expr; - return; + r = expr; + goto ret; } - + if(t->etype == TSTRUCT && countfield(t) <= 4) { // Struct of four or fewer fields. // Inline comparisons. @@ -3075,13 +3111,10 @@ walkcompare(Node **np, NodeList **init) } if(expr == N) expr = nodbool(n->op == OEQ); - typecheck(&expr, Erv); - walkexpr(&expr, init); - expr->type = n->type; - *np = expr; - return; + r = expr; + goto ret; } - + // Chose not to inline, but still have addresses. // Call equality function directly. // The equality function requires a bool pointer for @@ -3114,10 +3147,7 @@ walkcompare(Node **np, NodeList **init) if(n->op != OEQ) r = nod(ONOT, r, N); - typecheck(&r, Erv); - walkexpr(&r, init); - *np = r; - return; + goto ret; hard: // Cannot take address of one or both of the operands. @@ -3133,7 +3163,16 @@ hard: r = mkcall1(fn, n->type, init, typename(n->left->type), l, r); if(n->op == ONE) { r = nod(ONOT, r, N); - typecheck(&r, Erv); + } + goto ret; + +ret: + typecheck(&r, Erv); + walkexpr(&r, init); + if(r->type != n->type) { + r = nod(OCONVNOP, r, N); + r->type = n->type; + r->typecheck = 1; } *np = r; return; diff --git a/src/cmd/gc/y.tab.c b/src/cmd/gc/y.tab.c index 390ad80b3..08d8ecff2 100644 --- a/src/cmd/gc/y.tab.c +++ b/src/cmd/gc/y.tab.c @@ -1,21 +1,24 @@ -/* A Bison parser, made by GNU Bison 2.5. */ +/* A Bison parser, made by GNU Bison 2.3. */ -/* Bison implementation for Yacc-like parsers in C - - Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify +/* Skeleton implementation for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - + the Free Software Foundation; either version 2, or (at your option) + any later version. + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License - along with this program. If not, see . */ + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work @@ -26,7 +29,7 @@ special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. - + This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ @@ -44,7 +47,7 @@ #define YYBISON 1 /* Bison version. */ -#define YYBISON_VERSION "2.5" +#define YYBISON_VERSION "2.3" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -52,52 +55,11 @@ /* Pure parsers. */ #define YYPURE 0 -/* Push parsers. */ -#define YYPUSH 0 - -/* Pull parsers. */ -#define YYPULL 1 - /* Using locations. */ #define YYLSP_NEEDED 0 -/* Copy the first part of user declarations. */ - -/* Line 268 of yacc.c */ -#line 20 "go.y" - -#include -#include /* if we don't, bison will, and go.h re-#defines getc */ -#include -#include "go.h" - -static void fixlbrace(int); - - -/* Line 268 of yacc.c */ -#line 81 "y.tab.c" - -/* Enabling traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif - -/* Enabling verbose error messages. */ -#ifdef YYERROR_VERBOSE -# undef YYERROR_VERBOSE -# define YYERROR_VERBOSE 1 -#else -# define YYERROR_VERBOSE 1 -#endif - -/* Enabling the token table. */ -#ifndef YYTOKEN_TABLE -# define YYTOKEN_TABLE 0 -#endif - - /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE @@ -209,36 +171,61 @@ static void fixlbrace(int); +/* Copy the first part of user declarations. */ +#line 20 "go.y" + +#include +#include /* if we don't, bison will, and go.h re-#defines getc */ +#include +#include "go.h" + +static void fixlbrace(int); + + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 1 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE -{ - -/* Line 293 of yacc.c */ #line 28 "go.y" - +{ Node* node; NodeList* list; Type* type; Sym* sym; struct Val val; int i; - - - -/* Line 293 of yacc.c */ -#line 230 "y.tab.c" -} YYSTYPE; -# define YYSTYPE_IS_TRIVIAL 1 +} +/* Line 193 of yacc.c. */ +#line 216 "y.tab.c" + YYSTYPE; # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 #endif + /* Copy the second part of user declarations. */ -/* Line 343 of yacc.c */ -#line 242 "y.tab.c" +/* Line 216 of yacc.c. */ +#line 229 "y.tab.c" #ifdef short # undef short @@ -313,14 +300,14 @@ typedef short int yytype_int16; #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static int -YYID (int yyi) +YYID (int i) #else static int -YYID (yyi) - int yyi; +YYID (i) + int i; #endif { - return yyi; + return i; } #endif @@ -341,11 +328,11 @@ YYID (yyi) # define alloca _alloca # else # define YYSTACK_ALLOC alloca -# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ +# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) # include /* INFRINGES ON USER NAME SPACE */ -# ifndef EXIT_SUCCESS -# define EXIT_SUCCESS 0 +# ifndef _STDLIB_H +# define _STDLIB_H 1 # endif # endif # endif @@ -368,24 +355,24 @@ YYID (yyi) # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif -# if (defined __cplusplus && ! defined EXIT_SUCCESS \ +# if (defined __cplusplus && ! defined _STDLIB_H \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ -# ifndef EXIT_SUCCESS -# define EXIT_SUCCESS 0 +# ifndef _STDLIB_H +# define _STDLIB_H 1 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc -# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ +# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free -# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ +# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif @@ -401,9 +388,9 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */ /* A type that is properly aligned for any stack member. */ union yyalloc { - yytype_int16 yyss_alloc; - YYSTYPE yyvs_alloc; -}; + yytype_int16 yyss; + YYSTYPE yyvs; + }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) @@ -414,27 +401,6 @@ union yyalloc ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) -# define YYCOPY_NEEDED 1 - -/* Relocate STACK from its old location to the new one. The - local variables YYSIZE and YYSTACKSIZE give the old and new number of - elements in the stack, and YYPTR gives the new location of the - stack. Advance YYPTR to a properly aligned location for the next - stack. */ -# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ - do \ - { \ - YYSIZE_T yynewbytes; \ - YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ - Stack = &yyptr->Stack_alloc; \ - yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ - yyptr += yynewbytes / sizeof (*yyptr); \ - } \ - while (YYID (0)) - -#endif - -#if defined YYCOPY_NEEDED && YYCOPY_NEEDED /* Copy COUNT objects from FROM to TO. The source and destination do not overlap. */ # ifndef YYCOPY @@ -452,7 +418,24 @@ union yyalloc while (YYID (0)) # endif # endif -#endif /* !YYCOPY_NEEDED */ + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack, Stack, yysize); \ + Stack = &yyptr->Stack; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif /* YYFINAL -- State number of the termination state. */ #define YYFINAL 4 @@ -681,36 +664,36 @@ static const yytype_uint16 yyrline[] = 308, 312, 316, 322, 328, 334, 339, 343, 347, 353, 359, 363, 367, 373, 377, 383, 384, 388, 394, 403, 409, 427, 432, 444, 460, 465, 472, 492, 510, 519, - 538, 537, 552, 551, 582, 585, 592, 591, 602, 608, - 617, 628, 634, 637, 645, 644, 655, 661, 673, 677, - 682, 672, 703, 702, 715, 718, 724, 727, 739, 743, - 738, 761, 760, 776, 777, 781, 785, 789, 793, 797, - 801, 805, 809, 813, 817, 821, 825, 829, 833, 837, - 841, 845, 849, 854, 860, 861, 865, 876, 880, 884, - 888, 893, 897, 907, 911, 916, 924, 928, 929, 940, - 944, 948, 952, 956, 964, 965, 971, 978, 984, 991, - 994, 1001, 1007, 1024, 1031, 1032, 1039, 1040, 1059, 1060, - 1063, 1066, 1070, 1081, 1090, 1096, 1099, 1102, 1109, 1110, - 1116, 1129, 1144, 1152, 1164, 1169, 1175, 1176, 1177, 1178, - 1179, 1180, 1186, 1187, 1188, 1189, 1195, 1196, 1197, 1198, - 1199, 1205, 1206, 1209, 1212, 1213, 1214, 1215, 1216, 1219, - 1220, 1233, 1237, 1242, 1247, 1252, 1256, 1257, 1260, 1266, - 1273, 1279, 1286, 1292, 1303, 1317, 1346, 1386, 1411, 1429, - 1438, 1441, 1449, 1453, 1457, 1464, 1470, 1475, 1487, 1490, - 1500, 1501, 1507, 1508, 1514, 1518, 1524, 1525, 1531, 1535, - 1541, 1564, 1569, 1575, 1581, 1588, 1597, 1606, 1621, 1627, - 1632, 1636, 1643, 1656, 1657, 1663, 1669, 1672, 1676, 1682, - 1685, 1694, 1697, 1698, 1702, 1703, 1709, 1710, 1711, 1712, - 1713, 1715, 1714, 1729, 1734, 1738, 1742, 1746, 1750, 1755, - 1774, 1780, 1788, 1792, 1798, 1802, 1808, 1812, 1818, 1822, - 1831, 1835, 1839, 1843, 1849, 1852, 1860, 1861, 1863, 1864, - 1867, 1870, 1873, 1876, 1879, 1882, 1885, 1888, 1891, 1894, - 1897, 1900, 1903, 1906, 1912, 1916, 1920, 1924, 1928, 1932, - 1952, 1959, 1970, 1971, 1972, 1975, 1976, 1979, 1983, 1993, - 1997, 2001, 2005, 2009, 2013, 2017, 2023, 2029, 2037, 2045, - 2051, 2058, 2074, 2096, 2100, 2106, 2109, 2112, 2116, 2126, - 2130, 2145, 2153, 2154, 2166, 2167, 2170, 2174, 2180, 2184, - 2190, 2194 + 538, 537, 552, 551, 583, 586, 593, 592, 603, 609, + 618, 629, 635, 638, 646, 645, 656, 662, 674, 678, + 683, 673, 704, 703, 716, 719, 725, 728, 740, 744, + 739, 762, 761, 777, 778, 782, 786, 790, 794, 798, + 802, 806, 810, 814, 818, 822, 826, 830, 834, 838, + 842, 846, 850, 855, 861, 862, 866, 877, 881, 885, + 889, 894, 898, 908, 912, 917, 925, 929, 930, 941, + 945, 949, 953, 957, 965, 966, 972, 979, 985, 992, + 995, 1002, 1008, 1025, 1032, 1033, 1040, 1041, 1060, 1061, + 1064, 1067, 1071, 1082, 1091, 1097, 1100, 1103, 1110, 1111, + 1117, 1130, 1145, 1153, 1165, 1170, 1176, 1177, 1178, 1179, + 1180, 1181, 1187, 1188, 1189, 1190, 1196, 1197, 1198, 1199, + 1200, 1206, 1207, 1210, 1213, 1214, 1215, 1216, 1217, 1220, + 1221, 1234, 1238, 1243, 1248, 1253, 1257, 1258, 1261, 1267, + 1274, 1280, 1287, 1293, 1304, 1318, 1347, 1387, 1412, 1430, + 1439, 1442, 1450, 1454, 1458, 1465, 1471, 1476, 1488, 1491, + 1501, 1502, 1508, 1509, 1515, 1519, 1525, 1526, 1532, 1536, + 1542, 1565, 1570, 1576, 1582, 1589, 1598, 1607, 1622, 1628, + 1633, 1637, 1644, 1657, 1658, 1664, 1670, 1673, 1677, 1683, + 1686, 1695, 1698, 1699, 1703, 1704, 1710, 1711, 1712, 1713, + 1714, 1716, 1715, 1730, 1736, 1740, 1744, 1748, 1752, 1757, + 1776, 1782, 1790, 1794, 1800, 1804, 1810, 1814, 1820, 1824, + 1833, 1837, 1841, 1845, 1851, 1854, 1862, 1863, 1865, 1866, + 1869, 1872, 1875, 1878, 1881, 1884, 1887, 1890, 1893, 1896, + 1899, 1902, 1905, 1908, 1914, 1918, 1922, 1926, 1930, 1934, + 1954, 1961, 1972, 1973, 1974, 1977, 1978, 1981, 1985, 1995, + 1999, 2003, 2007, 2011, 2015, 2019, 2025, 2031, 2039, 2047, + 2053, 2060, 2076, 2098, 2102, 2108, 2111, 2114, 2118, 2128, + 2132, 2151, 2159, 2160, 2172, 2173, 2176, 2180, 2186, 2190, + 2196, 2200 }; #endif @@ -729,16 +712,16 @@ const char *yytname[] = "'/'", "'%'", "'&'", "NotPackage", "NotParen", "'('", "')'", "PreferToRightParen", "';'", "'.'", "'$'", "'='", "':'", "'{'", "'}'", "'!'", "'~'", "'['", "']'", "'?'", "'@'", "','", "$accept", "file", - "package", "loadsys", "$@1", "imports", "import", "import_stmt", + "package", "loadsys", "@1", "imports", "import", "import_stmt", "import_stmt_list", "import_here", "import_package", "import_safety", - "import_there", "$@2", "xdcl", "common_dcl", "lconst", "vardcl", + "import_there", "@2", "xdcl", "common_dcl", "lconst", "vardcl", "constdcl", "constdcl1", "typedclname", "typedcl", "simple_stmt", "case", - "compound_stmt", "$@3", "caseblock", "$@4", "caseblock_list", - "loop_body", "$@5", "range_stmt", "for_header", "for_body", "for_stmt", - "$@6", "if_header", "if_stmt", "$@7", "$@8", "$@9", "elseif", "$@10", - "elseif_list", "else", "switch_stmt", "$@11", "$@12", "select_stmt", - "$@13", "expr", "uexpr", "pseudocall", "pexpr_no_paren", "start_complit", - "keyval", "bare_complitexpr", "complitexpr", "pexpr", "expr_or_type", + "compound_stmt", "@3", "caseblock", "@4", "caseblock_list", "loop_body", + "@5", "range_stmt", "for_header", "for_body", "for_stmt", "@6", + "if_header", "if_stmt", "@7", "@8", "@9", "elseif", "@10", "elseif_list", + "else", "switch_stmt", "@11", "@12", "select_stmt", "@13", "expr", + "uexpr", "pseudocall", "pexpr_no_paren", "start_complit", "keyval", + "bare_complitexpr", "complitexpr", "pexpr", "expr_or_type", "name_or_type", "lbrace", "new_name", "dcl_name", "onew_name", "sym", "hidden_importsym", "name", "labelname", "dotdotdot", "ntype", "non_expr_type", "non_recvchantype", "convtype", "comptype", @@ -748,7 +731,7 @@ const char *yytname[] = "vardcl_list", "constdcl_list", "typedcl_list", "structdcl_list", "interfacedcl_list", "structdcl", "packname", "embed", "interfacedcl", "indcl", "arg_type", "arg_type_list", "oarg_type_list_ocomma", "stmt", - "non_dcl_stmt", "$@14", "stmt_list", "new_name_list", "dcl_name_list", + "non_dcl_stmt", "@14", "stmt_list", "new_name_list", "dcl_name_list", "expr_list", "expr_or_type_list", "keyval_list", "braced_keyval_list", "osemi", "ocomma", "oexpr", "oexpr_list", "osimple_stmt", "ohidden_funarg_list", "ohidden_structdcl_list", @@ -861,8 +844,8 @@ static const yytype_uint8 yyr2[] = 1, 3 }; -/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM. - Performed when YYTABLE doesn't specify something else to do. Zero +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero means the default is an error. */ static const yytype_uint16 yydefact[] = { @@ -1051,7 +1034,8 @@ static const yytype_int16 yypgoto[] = /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which - number is the opposite. If YYTABLE_NINF, syntax error. */ + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ #define YYTABLE_NINF -277 static const yytype_int16 yytable[] = { @@ -1285,12 +1269,6 @@ static const yytype_int16 yytable[] = 198 }; -#define yypact_value_is_default(yystate) \ - ((yystate) == (-474)) - -#define yytable_value_is_error(yytable_value) \ - YYID (0) - static const yytype_int16 yycheck[] = { 37, 37, 61, 143, 67, 37, 37, 202, 324, 251, @@ -1608,18 +1586,9 @@ static const yytype_uint8 yystos[] = /* Like YYERROR except do call yyerror. This remains here temporarily to ease the transition to the new meaning of YYERROR, for GCC. - Once GCC version 2 has supplanted version 1, this can go. However, - YYFAIL appears to be in use. Nevertheless, it is formally deprecated - in Bison 2.4.2's NEWS entry, where a plan to phase it out is - discussed. */ + Once GCC version 2 has supplanted version 1, this can go. */ #define YYFAIL goto yyerrlab -#if defined YYFAIL - /* This is here to suppress warnings from the GCC cpp's - -Wunused-macros. Normally we don't worry about that warning, but - some users do, and we want to make it easy for users to remove - YYFAIL uses, which will produce warnings from Bison 2.5. */ -#endif #define YYRECOVERING() (!!yyerrstatus) @@ -1629,6 +1598,7 @@ do \ { \ yychar = (Token); \ yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ YYPOPSTACK (1); \ goto yybackup; \ } \ @@ -1670,10 +1640,19 @@ while (YYID (0)) #endif -/* This macro is provided for backward compatibility. */ +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ #ifndef YY_LOCATION_PRINT -# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif #endif @@ -1777,20 +1756,17 @@ yy_symbol_print (yyoutput, yytype, yyvaluep) #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void -yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +yy_stack_print (yytype_int16 *bottom, yytype_int16 *top) #else static void -yy_stack_print (yybottom, yytop) - yytype_int16 *yybottom; - yytype_int16 *yytop; +yy_stack_print (bottom, top) + yytype_int16 *bottom; + yytype_int16 *top; #endif { YYFPRINTF (stderr, "Stack now"); - for (; yybottom <= yytop; yybottom++) - { - int yybot = *yybottom; - YYFPRINTF (stderr, " %d", yybot); - } + for (; bottom <= top; ++bottom) + YYFPRINTF (stderr, " %d", *bottom); YYFPRINTF (stderr, "\n"); } @@ -1824,11 +1800,11 @@ yy_reduce_print (yyvsp, yyrule) /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { - YYFPRINTF (stderr, " $%d = ", yyi + 1); + fprintf (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], &(yyvsp[(yyi + 1) - (yynrhs)]) ); - YYFPRINTF (stderr, "\n"); + fprintf (stderr, "\n"); } } @@ -1865,6 +1841,7 @@ int yydebug; # define YYMAXDEPTH 10000 #endif + #if YYERROR_VERBOSE @@ -1967,142 +1944,115 @@ yytnamerr (char *yyres, const char *yystr) } # endif -/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message - about the unexpected token YYTOKEN for the state stack whose top is - YYSSP. - - Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is - not large enough to hold the message. In that case, also set - *YYMSG_ALLOC to the required number of bytes. Return 2 if the - required number of bytes is too large to store. */ -static int -yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, - yytype_int16 *yyssp, int yytoken) +/* Copy into YYRESULT an error message about the unexpected token + YYCHAR while in state YYSTATE. Return the number of bytes copied, + including the terminating null byte. If YYRESULT is null, do not + copy anything; just return the number of bytes that would be + copied. As a special case, return 0 if an ordinary "syntax error" + message will do. Return YYSIZE_MAXIMUM if overflow occurs during + size calculation. */ +static YYSIZE_T +yysyntax_error (char *yyresult, int yystate, int yychar) { - YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]); - YYSIZE_T yysize = yysize0; - YYSIZE_T yysize1; - enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; - /* Internationalized format string. */ - const char *yyformat = 0; - /* Arguments of yyformat. */ - char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; - /* Number of reported tokens (one for the "unexpected", one per - "expected"). */ - int yycount = 0; - - /* There are many possibilities here to consider: - - Assume YYFAIL is not used. It's too flawed to consider. See - - for details. YYERROR is fine as it does not invoke this - function. - - If this state is a consistent state with a default action, then - the only way this function was invoked is if the default action - is an error action. In that case, don't check for expected - tokens because there are none. - - The only way there can be no lookahead present (in yychar) is if - this state is a consistent state with a default action. Thus, - detecting the absence of a lookahead is sufficient to determine - that there is no unexpected or expected token to report. In that - case, just report a simple "syntax error". - - Don't assume there isn't a lookahead just because this state is a - consistent state with a default action. There might have been a - previous inconsistent state, consistent state with a non-default - action, or user semantic action that manipulated yychar. - - Of course, the expected token list depends on states to have - correct lookahead information, and it depends on the parser not - to perform extra reductions after fetching a lookahead from the - scanner and before detecting a syntax error. Thus, state merging - (from LALR or IELR) and default reductions corrupt the expected - token list. However, the list is correct for canonical LR with - one exception: it will still contain any token that will not be - accepted due to an error action in a later state. - */ - if (yytoken != YYEMPTY) - { - int yyn = yypact[*yyssp]; - yyarg[yycount++] = yytname[yytoken]; - if (!yypact_value_is_default (yyn)) - { - /* Start YYX at -YYN if negative to avoid negative indexes in - YYCHECK. In other words, skip the first -YYN actions for - this state because they are default actions. */ - int yyxbegin = yyn < 0 ? -yyn : 0; - /* Stay within bounds of both yycheck and yytname. */ - int yychecklim = YYLAST - yyn + 1; - int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; - int yyx; - - for (yyx = yyxbegin; yyx < yyxend; ++yyx) - if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR - && !yytable_value_is_error (yytable[yyx + yyn])) - { - if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) - { - yycount = 1; - yysize = yysize0; - break; - } - yyarg[yycount++] = yytname[yyx]; - yysize1 = yysize + yytnamerr (0, yytname[yyx]); - if (! (yysize <= yysize1 - && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) - return 2; - yysize = yysize1; - } - } - } + int yyn = yypact[yystate]; - switch (yycount) - { -# define YYCASE_(N, S) \ - case N: \ - yyformat = S; \ - break - YYCASE_(0, YY_("syntax error")); - YYCASE_(1, YY_("syntax error, unexpected %s")); - YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); - YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); - YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); - YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); -# undef YYCASE_ - } + if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) + return 0; + else + { + int yytype = YYTRANSLATE (yychar); + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + int yysize_overflow = 0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int yyx; + +# if 0 + /* This is so xgettext sees the translatable formats that are + constructed on the fly. */ + YY_("syntax error, unexpected %s"); + YY_("syntax error, unexpected %s, expecting %s"); + YY_("syntax error, unexpected %s, expecting %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); +# endif + char *yyfmt; + char const *yyf; + static char const yyunexpected[] = "syntax error, unexpected %s"; + static char const yyexpecting[] = ", expecting %s"; + static char const yyor[] = " or %s"; + char yyformat[sizeof yyunexpected + + sizeof yyexpecting - 1 + + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) + * (sizeof yyor - 1))]; + char const *yyprefix = yyexpecting; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 1; + + yyarg[0] = yytname[yytype]; + yyfmt = yystpcpy (yyformat, yyunexpected); + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + yyformat[sizeof yyunexpected - 1] = '\0'; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + yyfmt = yystpcpy (yyfmt, yyprefix); + yyprefix = yyor; + } - yysize1 = yysize + yystrlen (yyformat); - if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) - return 2; - yysize = yysize1; + yyf = YY_(yyformat); + yysize1 = yysize + yystrlen (yyf); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; - if (*yymsg_alloc < yysize) - { - *yymsg_alloc = 2 * yysize; - if (! (yysize <= *yymsg_alloc - && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) - *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; - return 1; - } + if (yysize_overflow) + return YYSIZE_MAXIMUM; - /* Avoid sprintf, as that infringes on the user's name space. - Don't have undefined behavior even if the translation - produced a string with the wrong number of "%s"s. */ - { - char *yyp = *yymsg; - int yyi = 0; - while ((*yyp = *yyformat) != '\0') - if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) - { - yyp += yytnamerr (yyp, yyarg[yyi++]); - yyformat += 2; - } - else - { - yyp++; - yyformat++; - } - } - return 0; + if (yyresult) + { + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + char *yyp = yyresult; + int yyi = 0; + while ((*yyp = *yyf) != '\0') + { + if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyf += 2; + } + else + { + yyp++; + yyf++; + } + } + } + return yysize; + } } #endif /* YYERROR_VERBOSE */ + /*-----------------------------------------------. | Release the memory associated to this symbol. | @@ -2134,9 +2084,10 @@ yydestruct (yymsg, yytype, yyvaluep) break; } } - + /* Prevent warnings from -Wmissing-prototypes. */ + #ifdef YYPARSE_PARAM #if defined __STDC__ || defined __cplusplus int yyparse (void *YYPARSE_PARAM); @@ -2152,16 +2103,18 @@ int yyparse (); #endif /* ! YYPARSE_PARAM */ -/* The lookahead symbol. */ + +/* The look-ahead symbol. */ int yychar, yystate; -/* The semantic value of the lookahead symbol. */ +/* The semantic value of the look-ahead symbol. */ YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; + /*----------. | yyparse. | `----------*/ @@ -2188,36 +2141,13 @@ yyparse () #endif #endif { - /* Number of tokens to shift before error messages enabled. */ - int yyerrstatus; - - /* The stacks and their tools: - `yyss': related to states. - `yyvs': related to semantic values. - - Refer to the stacks thru separate pointers, to allow yyoverflow - to reallocate them elsewhere. */ - - /* The state stack. */ - yytype_int16 yyssa[YYINITDEPTH]; - yytype_int16 *yyss; - yytype_int16 *yyssp; - - /* The semantic value stack. */ - YYSTYPE yyvsa[YYINITDEPTH]; - YYSTYPE *yyvs; - YYSTYPE *yyvsp; - - YYSIZE_T yystacksize; - + int yyn; int yyresult; - /* Lookahead token as an internal (translated) token number. */ - int yytoken; - /* The variables used to return semantic value and location from the - action routines. */ - YYSTYPE yyval; - + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Look-ahead token as an internal (translated) token number. */ + int yytoken = 0; #if YYERROR_VERBOSE /* Buffer for error messages, and its allocated size. */ char yymsgbuf[128]; @@ -2225,28 +2155,51 @@ yyparse () YYSIZE_T yymsg_alloc = sizeof yymsgbuf; #endif + /* Three stacks and their tools: + `yyss': related to states, + `yyvs': related to semantic values, + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss = yyssa; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + YYSTYPE *yyvsp; + + + #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + YYSIZE_T yystacksize = YYINITDEPTH; + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + + /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; - yytoken = 0; - yyss = yyssa; - yyvs = yyvsa; - yystacksize = YYINITDEPTH; - YYDPRINTF ((stderr, "Starting parse\n")); yystate = 0; yyerrstatus = 0; yynerrs = 0; - yychar = YYEMPTY; /* Cause a token to be read. */ + yychar = YYEMPTY; /* Cause a token to be read. */ /* Initialize stack pointers. Waste one element of value and location stack so that they stay on the same level as the state stack. The wasted elements are never initialized. */ + yyssp = yyss; yyvsp = yyvs; @@ -2276,6 +2229,7 @@ yyparse () YYSTYPE *yyvs1 = yyvs; yytype_int16 *yyss1 = yyss; + /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might @@ -2283,6 +2237,7 @@ yyparse () yyoverflow (YY_("memory exhausted"), &yyss1, yysize * sizeof (*yyssp), &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); yyss = yyss1; @@ -2305,8 +2260,9 @@ yyparse () (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); if (! yyptr) goto yyexhaustedlab; - YYSTACK_RELOCATE (yyss_alloc, yyss); - YYSTACK_RELOCATE (yyvs_alloc, yyvs); + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); + # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); @@ -2317,6 +2273,7 @@ yyparse () yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; + YYDPRINTF ((stderr, "Stack size increased to %lu\n", (unsigned long int) yystacksize)); @@ -2326,9 +2283,6 @@ yyparse () YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - if (yystate == YYFINAL) - YYACCEPT; - goto yybackup; /*-----------. @@ -2337,16 +2291,16 @@ yyparse () yybackup: /* Do appropriate processing given the current state. Read a - lookahead token if we need one and don't already have one. */ + look-ahead token if we need one and don't already have one. */ - /* First try to decide what to do without reference to lookahead token. */ + /* First try to decide what to do without reference to look-ahead token. */ yyn = yypact[yystate]; - if (yypact_value_is_default (yyn)) + if (yyn == YYPACT_NINF) goto yydefault; - /* Not known => get a lookahead token if don't already have one. */ + /* Not known => get a look-ahead token if don't already have one. */ - /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token: ")); @@ -2372,22 +2326,26 @@ yybackup: yyn = yytable[yyn]; if (yyn <= 0) { - if (yytable_value_is_error (yyn)) - goto yyerrlab; + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; yyn = -yyn; goto yyreduce; } + if (yyn == YYFINAL) + YYACCEPT; + /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; - /* Shift the lookahead token. */ + /* Shift the look-ahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); - /* Discard the shifted token. */ - yychar = YYEMPTY; + /* Discard the shifted token unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; yystate = yyn; *++yyvsp = yylval; @@ -2427,8 +2385,6 @@ yyreduce: switch (yyn) { case 2: - -/* Line 1806 of yacc.c */ #line 128 "go.y" { xtop = concat(xtop, (yyvsp[(4) - (4)].list)); @@ -2436,8 +2392,6 @@ yyreduce: break; case 3: - -/* Line 1806 of yacc.c */ #line 134 "go.y" { prevlineno = lineno; @@ -2447,8 +2401,6 @@ yyreduce: break; case 4: - -/* Line 1806 of yacc.c */ #line 140 "go.y" { mkpackage((yyvsp[(2) - (3)].sym)->name); @@ -2456,8 +2408,6 @@ yyreduce: break; case 5: - -/* Line 1806 of yacc.c */ #line 150 "go.y" { importpkg = runtimepkg; @@ -2471,8 +2421,6 @@ yyreduce: break; case 6: - -/* Line 1806 of yacc.c */ #line 161 "go.y" { importpkg = nil; @@ -2480,8 +2428,6 @@ yyreduce: break; case 12: - -/* Line 1806 of yacc.c */ #line 175 "go.y" { Pkg *ipkg; @@ -2522,8 +2468,6 @@ yyreduce: break; case 13: - -/* Line 1806 of yacc.c */ #line 212 "go.y" { // When an invalid import path is passed to importfile, @@ -2536,8 +2480,6 @@ yyreduce: break; case 16: - -/* Line 1806 of yacc.c */ #line 227 "go.y" { // import with original name @@ -2548,8 +2490,6 @@ yyreduce: break; case 17: - -/* Line 1806 of yacc.c */ #line 234 "go.y" { // import with given name @@ -2560,8 +2500,6 @@ yyreduce: break; case 18: - -/* Line 1806 of yacc.c */ #line 241 "go.y" { // import into my name space @@ -2572,8 +2510,6 @@ yyreduce: break; case 19: - -/* Line 1806 of yacc.c */ #line 250 "go.y" { if(importpkg->name == nil) { @@ -2590,8 +2526,6 @@ yyreduce: break; case 21: - -/* Line 1806 of yacc.c */ #line 265 "go.y" { if(strcmp((yyvsp[(1) - (1)].sym)->name, "safe") == 0) @@ -2600,8 +2534,6 @@ yyreduce: break; case 22: - -/* Line 1806 of yacc.c */ #line 271 "go.y" { defercheckwidth(); @@ -2609,8 +2541,6 @@ yyreduce: break; case 23: - -/* Line 1806 of yacc.c */ #line 275 "go.y" { resumecheckwidth(); @@ -2619,8 +2549,6 @@ yyreduce: break; case 24: - -/* Line 1806 of yacc.c */ #line 284 "go.y" { yyerror("empty top-level declaration"); @@ -2629,8 +2557,6 @@ yyreduce: break; case 26: - -/* Line 1806 of yacc.c */ #line 290 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); @@ -2638,8 +2564,6 @@ yyreduce: break; case 27: - -/* Line 1806 of yacc.c */ #line 294 "go.y" { yyerror("non-declaration statement outside function body"); @@ -2648,8 +2572,6 @@ yyreduce: break; case 28: - -/* Line 1806 of yacc.c */ #line 299 "go.y" { (yyval.list) = nil; @@ -2657,8 +2579,6 @@ yyreduce: break; case 29: - -/* Line 1806 of yacc.c */ #line 305 "go.y" { (yyval.list) = (yyvsp[(2) - (2)].list); @@ -2666,8 +2586,6 @@ yyreduce: break; case 30: - -/* Line 1806 of yacc.c */ #line 309 "go.y" { (yyval.list) = (yyvsp[(3) - (5)].list); @@ -2675,8 +2593,6 @@ yyreduce: break; case 31: - -/* Line 1806 of yacc.c */ #line 313 "go.y" { (yyval.list) = nil; @@ -2684,8 +2600,6 @@ yyreduce: break; case 32: - -/* Line 1806 of yacc.c */ #line 317 "go.y" { (yyval.list) = (yyvsp[(2) - (2)].list); @@ -2695,8 +2609,6 @@ yyreduce: break; case 33: - -/* Line 1806 of yacc.c */ #line 323 "go.y" { (yyval.list) = (yyvsp[(3) - (5)].list); @@ -2706,8 +2618,6 @@ yyreduce: break; case 34: - -/* Line 1806 of yacc.c */ #line 329 "go.y" { (yyval.list) = concat((yyvsp[(3) - (7)].list), (yyvsp[(5) - (7)].list)); @@ -2717,8 +2627,6 @@ yyreduce: break; case 35: - -/* Line 1806 of yacc.c */ #line 335 "go.y" { (yyval.list) = nil; @@ -2727,8 +2635,6 @@ yyreduce: break; case 36: - -/* Line 1806 of yacc.c */ #line 340 "go.y" { (yyval.list) = list1((yyvsp[(2) - (2)].node)); @@ -2736,8 +2642,6 @@ yyreduce: break; case 37: - -/* Line 1806 of yacc.c */ #line 344 "go.y" { (yyval.list) = (yyvsp[(3) - (5)].list); @@ -2745,8 +2649,6 @@ yyreduce: break; case 38: - -/* Line 1806 of yacc.c */ #line 348 "go.y" { (yyval.list) = nil; @@ -2754,8 +2656,6 @@ yyreduce: break; case 39: - -/* Line 1806 of yacc.c */ #line 354 "go.y" { iota = 0; @@ -2763,8 +2663,6 @@ yyreduce: break; case 40: - -/* Line 1806 of yacc.c */ #line 360 "go.y" { (yyval.list) = variter((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node), nil); @@ -2772,8 +2670,6 @@ yyreduce: break; case 41: - -/* Line 1806 of yacc.c */ #line 364 "go.y" { (yyval.list) = variter((yyvsp[(1) - (4)].list), (yyvsp[(2) - (4)].node), (yyvsp[(4) - (4)].list)); @@ -2781,8 +2677,6 @@ yyreduce: break; case 42: - -/* Line 1806 of yacc.c */ #line 368 "go.y" { (yyval.list) = variter((yyvsp[(1) - (3)].list), nil, (yyvsp[(3) - (3)].list)); @@ -2790,8 +2684,6 @@ yyreduce: break; case 43: - -/* Line 1806 of yacc.c */ #line 374 "go.y" { (yyval.list) = constiter((yyvsp[(1) - (4)].list), (yyvsp[(2) - (4)].node), (yyvsp[(4) - (4)].list)); @@ -2799,8 +2691,6 @@ yyreduce: break; case 44: - -/* Line 1806 of yacc.c */ #line 378 "go.y" { (yyval.list) = constiter((yyvsp[(1) - (3)].list), N, (yyvsp[(3) - (3)].list)); @@ -2808,8 +2698,6 @@ yyreduce: break; case 46: - -/* Line 1806 of yacc.c */ #line 385 "go.y" { (yyval.list) = constiter((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node), nil); @@ -2817,8 +2705,6 @@ yyreduce: break; case 47: - -/* Line 1806 of yacc.c */ #line 389 "go.y" { (yyval.list) = constiter((yyvsp[(1) - (1)].list), N, nil); @@ -2826,8 +2712,6 @@ yyreduce: break; case 48: - -/* Line 1806 of yacc.c */ #line 395 "go.y" { // different from dclname because the name @@ -2838,8 +2722,6 @@ yyreduce: break; case 49: - -/* Line 1806 of yacc.c */ #line 404 "go.y" { (yyval.node) = typedcl1((yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node), 1); @@ -2847,8 +2729,6 @@ yyreduce: break; case 50: - -/* Line 1806 of yacc.c */ #line 410 "go.y" { (yyval.node) = (yyvsp[(1) - (1)].node); @@ -2870,8 +2750,6 @@ yyreduce: break; case 51: - -/* Line 1806 of yacc.c */ #line 428 "go.y" { (yyval.node) = nod(OASOP, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2880,8 +2758,6 @@ yyreduce: break; case 52: - -/* Line 1806 of yacc.c */ #line 433 "go.y" { if((yyvsp[(1) - (3)].list)->next == nil && (yyvsp[(3) - (3)].list)->next == nil) { @@ -2897,8 +2773,6 @@ yyreduce: break; case 53: - -/* Line 1806 of yacc.c */ #line 445 "go.y" { if((yyvsp[(3) - (3)].list)->n->op == OTYPESW) { @@ -2918,8 +2792,6 @@ yyreduce: break; case 54: - -/* Line 1806 of yacc.c */ #line 461 "go.y" { (yyval.node) = nod(OASOP, (yyvsp[(1) - (2)].node), nodintconst(1)); @@ -2928,8 +2800,6 @@ yyreduce: break; case 55: - -/* Line 1806 of yacc.c */ #line 466 "go.y" { (yyval.node) = nod(OASOP, (yyvsp[(1) - (2)].node), nodintconst(1)); @@ -2938,8 +2808,6 @@ yyreduce: break; case 56: - -/* Line 1806 of yacc.c */ #line 473 "go.y" { Node *n, *nn; @@ -2963,8 +2831,6 @@ yyreduce: break; case 57: - -/* Line 1806 of yacc.c */ #line 493 "go.y" { Node *n; @@ -2986,8 +2852,6 @@ yyreduce: break; case 58: - -/* Line 1806 of yacc.c */ #line 511 "go.y" { // will be converted to OCASE @@ -3000,8 +2864,6 @@ yyreduce: break; case 59: - -/* Line 1806 of yacc.c */ #line 520 "go.y" { Node *n, *nn; @@ -3021,8 +2883,6 @@ yyreduce: break; case 60: - -/* Line 1806 of yacc.c */ #line 538 "go.y" { markdcl(); @@ -3030,8 +2890,6 @@ yyreduce: break; case 61: - -/* Line 1806 of yacc.c */ #line 542 "go.y" { if((yyvsp[(3) - (4)].list) == nil) @@ -3043,8 +2901,6 @@ yyreduce: break; case 62: - -/* Line 1806 of yacc.c */ #line 552 "go.y" { // If the last token read by the lexer was consumed @@ -3054,13 +2910,12 @@ yyreduce: // This is so that the stmt_list action doesn't look at // the case tokens if the stmt_list is empty. yylast = yychar; + (yyvsp[(1) - (1)].node)->xoffset = block; } break; case 63: - -/* Line 1806 of yacc.c */ -#line 562 "go.y" +#line 563 "go.y" { int last; @@ -3082,36 +2937,28 @@ yyreduce: break; case 64: - -/* Line 1806 of yacc.c */ -#line 582 "go.y" +#line 583 "go.y" { (yyval.list) = nil; } break; case 65: - -/* Line 1806 of yacc.c */ -#line 586 "go.y" +#line 587 "go.y" { (yyval.list) = list((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node)); } break; case 66: - -/* Line 1806 of yacc.c */ -#line 592 "go.y" +#line 593 "go.y" { markdcl(); } break; case 67: - -/* Line 1806 of yacc.c */ -#line 596 "go.y" +#line 597 "go.y" { (yyval.list) = (yyvsp[(3) - (4)].list); popdcl(); @@ -3119,9 +2966,7 @@ yyreduce: break; case 68: - -/* Line 1806 of yacc.c */ -#line 603 "go.y" +#line 604 "go.y" { (yyval.node) = nod(ORANGE, N, (yyvsp[(4) - (4)].node)); (yyval.node)->list = (yyvsp[(1) - (4)].list); @@ -3130,9 +2975,7 @@ yyreduce: break; case 69: - -/* Line 1806 of yacc.c */ -#line 609 "go.y" +#line 610 "go.y" { (yyval.node) = nod(ORANGE, N, (yyvsp[(4) - (4)].node)); (yyval.node)->list = (yyvsp[(1) - (4)].list); @@ -3142,9 +2985,7 @@ yyreduce: break; case 70: - -/* Line 1806 of yacc.c */ -#line 618 "go.y" +#line 619 "go.y" { // init ; test ; incr if((yyvsp[(5) - (5)].node) != N && (yyvsp[(5) - (5)].node)->colas != 0) @@ -3158,9 +2999,7 @@ yyreduce: break; case 71: - -/* Line 1806 of yacc.c */ -#line 629 "go.y" +#line 630 "go.y" { // normal test (yyval.node) = nod(OFOR, N, N); @@ -3169,9 +3008,7 @@ yyreduce: break; case 73: - -/* Line 1806 of yacc.c */ -#line 638 "go.y" +#line 639 "go.y" { (yyval.node) = (yyvsp[(1) - (2)].node); (yyval.node)->nbody = concat((yyval.node)->nbody, (yyvsp[(2) - (2)].list)); @@ -3179,18 +3016,14 @@ yyreduce: break; case 74: - -/* Line 1806 of yacc.c */ -#line 645 "go.y" +#line 646 "go.y" { markdcl(); } break; case 75: - -/* Line 1806 of yacc.c */ -#line 649 "go.y" +#line 650 "go.y" { (yyval.node) = (yyvsp[(3) - (3)].node); popdcl(); @@ -3198,9 +3031,7 @@ yyreduce: break; case 76: - -/* Line 1806 of yacc.c */ -#line 656 "go.y" +#line 657 "go.y" { // test (yyval.node) = nod(OIF, N, N); @@ -3209,9 +3040,7 @@ yyreduce: break; case 77: - -/* Line 1806 of yacc.c */ -#line 662 "go.y" +#line 663 "go.y" { // init ; test (yyval.node) = nod(OIF, N, N); @@ -3222,18 +3051,14 @@ yyreduce: break; case 78: - -/* Line 1806 of yacc.c */ -#line 673 "go.y" +#line 674 "go.y" { markdcl(); } break; case 79: - -/* Line 1806 of yacc.c */ -#line 677 "go.y" +#line 678 "go.y" { if((yyvsp[(3) - (3)].node)->ntest == N) yyerror("missing condition in if statement"); @@ -3241,18 +3066,14 @@ yyreduce: break; case 80: - -/* Line 1806 of yacc.c */ -#line 682 "go.y" +#line 683 "go.y" { (yyvsp[(3) - (5)].node)->nbody = (yyvsp[(5) - (5)].list); } break; case 81: - -/* Line 1806 of yacc.c */ -#line 686 "go.y" +#line 687 "go.y" { Node *n; NodeList *nn; @@ -3270,18 +3091,14 @@ yyreduce: break; case 82: - -/* Line 1806 of yacc.c */ -#line 703 "go.y" +#line 704 "go.y" { markdcl(); } break; case 83: - -/* Line 1806 of yacc.c */ -#line 707 "go.y" +#line 708 "go.y" { if((yyvsp[(4) - (5)].node)->ntest == N) yyerror("missing condition in if statement"); @@ -3291,36 +3108,28 @@ yyreduce: break; case 84: - -/* Line 1806 of yacc.c */ -#line 715 "go.y" +#line 716 "go.y" { (yyval.list) = nil; } break; case 85: - -/* Line 1806 of yacc.c */ -#line 719 "go.y" +#line 720 "go.y" { (yyval.list) = concat((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].list)); } break; case 86: - -/* Line 1806 of yacc.c */ -#line 724 "go.y" +#line 725 "go.y" { (yyval.list) = nil; } break; case 87: - -/* Line 1806 of yacc.c */ -#line 728 "go.y" +#line 729 "go.y" { NodeList *node; @@ -3332,18 +3141,14 @@ yyreduce: break; case 88: - -/* Line 1806 of yacc.c */ -#line 739 "go.y" +#line 740 "go.y" { markdcl(); } break; case 89: - -/* Line 1806 of yacc.c */ -#line 743 "go.y" +#line 744 "go.y" { Node *n; n = (yyvsp[(3) - (3)].node)->ntest; @@ -3354,9 +3159,7 @@ yyreduce: break; case 90: - -/* Line 1806 of yacc.c */ -#line 751 "go.y" +#line 752 "go.y" { (yyval.node) = (yyvsp[(3) - (7)].node); (yyval.node)->op = OSWITCH; @@ -3367,18 +3170,14 @@ yyreduce: break; case 91: - -/* Line 1806 of yacc.c */ -#line 761 "go.y" +#line 762 "go.y" { typesw = nod(OXXX, typesw, N); } break; case 92: - -/* Line 1806 of yacc.c */ -#line 765 "go.y" +#line 766 "go.y" { (yyval.node) = nod(OSELECT, N, N); (yyval.node)->lineno = typesw->lineno; @@ -3388,198 +3187,154 @@ yyreduce: break; case 94: - -/* Line 1806 of yacc.c */ -#line 778 "go.y" +#line 779 "go.y" { (yyval.node) = nod(OOROR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 95: - -/* Line 1806 of yacc.c */ -#line 782 "go.y" +#line 783 "go.y" { (yyval.node) = nod(OANDAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 96: - -/* Line 1806 of yacc.c */ -#line 786 "go.y" +#line 787 "go.y" { (yyval.node) = nod(OEQ, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 97: - -/* Line 1806 of yacc.c */ -#line 790 "go.y" +#line 791 "go.y" { (yyval.node) = nod(ONE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 98: - -/* Line 1806 of yacc.c */ -#line 794 "go.y" +#line 795 "go.y" { (yyval.node) = nod(OLT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 99: - -/* Line 1806 of yacc.c */ -#line 798 "go.y" +#line 799 "go.y" { (yyval.node) = nod(OLE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 100: - -/* Line 1806 of yacc.c */ -#line 802 "go.y" +#line 803 "go.y" { (yyval.node) = nod(OGE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 101: - -/* Line 1806 of yacc.c */ -#line 806 "go.y" +#line 807 "go.y" { (yyval.node) = nod(OGT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 102: - -/* Line 1806 of yacc.c */ -#line 810 "go.y" +#line 811 "go.y" { (yyval.node) = nod(OADD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 103: - -/* Line 1806 of yacc.c */ -#line 814 "go.y" +#line 815 "go.y" { (yyval.node) = nod(OSUB, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 104: - -/* Line 1806 of yacc.c */ -#line 818 "go.y" +#line 819 "go.y" { (yyval.node) = nod(OOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 105: - -/* Line 1806 of yacc.c */ -#line 822 "go.y" +#line 823 "go.y" { (yyval.node) = nod(OXOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 106: - -/* Line 1806 of yacc.c */ -#line 826 "go.y" +#line 827 "go.y" { (yyval.node) = nod(OMUL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 107: - -/* Line 1806 of yacc.c */ -#line 830 "go.y" +#line 831 "go.y" { (yyval.node) = nod(ODIV, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 108: - -/* Line 1806 of yacc.c */ -#line 834 "go.y" +#line 835 "go.y" { (yyval.node) = nod(OMOD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 109: - -/* Line 1806 of yacc.c */ -#line 838 "go.y" +#line 839 "go.y" { (yyval.node) = nod(OAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 110: - -/* Line 1806 of yacc.c */ -#line 842 "go.y" +#line 843 "go.y" { (yyval.node) = nod(OANDNOT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 111: - -/* Line 1806 of yacc.c */ -#line 846 "go.y" +#line 847 "go.y" { (yyval.node) = nod(OLSH, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 112: - -/* Line 1806 of yacc.c */ -#line 850 "go.y" +#line 851 "go.y" { (yyval.node) = nod(ORSH, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 113: - -/* Line 1806 of yacc.c */ -#line 855 "go.y" +#line 856 "go.y" { (yyval.node) = nod(OSEND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 115: - -/* Line 1806 of yacc.c */ -#line 862 "go.y" +#line 863 "go.y" { (yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N); } break; case 116: - -/* Line 1806 of yacc.c */ -#line 866 "go.y" +#line 867 "go.y" { if((yyvsp[(2) - (2)].node)->op == OCOMPLIT) { // Special case for &T{...}: turn into (*T){...}. @@ -3593,36 +3348,28 @@ yyreduce: break; case 117: - -/* Line 1806 of yacc.c */ -#line 877 "go.y" +#line 878 "go.y" { (yyval.node) = nod(OPLUS, (yyvsp[(2) - (2)].node), N); } break; case 118: - -/* Line 1806 of yacc.c */ -#line 881 "go.y" +#line 882 "go.y" { (yyval.node) = nod(OMINUS, (yyvsp[(2) - (2)].node), N); } break; case 119: - -/* Line 1806 of yacc.c */ -#line 885 "go.y" +#line 886 "go.y" { (yyval.node) = nod(ONOT, (yyvsp[(2) - (2)].node), N); } break; case 120: - -/* Line 1806 of yacc.c */ -#line 889 "go.y" +#line 890 "go.y" { yyerror("the bitwise complement operator is ^"); (yyval.node) = nod(OCOM, (yyvsp[(2) - (2)].node), N); @@ -3630,36 +3377,28 @@ yyreduce: break; case 121: - -/* Line 1806 of yacc.c */ -#line 894 "go.y" +#line 895 "go.y" { (yyval.node) = nod(OCOM, (yyvsp[(2) - (2)].node), N); } break; case 122: - -/* Line 1806 of yacc.c */ -#line 898 "go.y" +#line 899 "go.y" { (yyval.node) = nod(ORECV, (yyvsp[(2) - (2)].node), N); } break; case 123: - -/* Line 1806 of yacc.c */ -#line 908 "go.y" +#line 909 "go.y" { (yyval.node) = nod(OCALL, (yyvsp[(1) - (3)].node), N); } break; case 124: - -/* Line 1806 of yacc.c */ -#line 912 "go.y" +#line 913 "go.y" { (yyval.node) = nod(OCALL, (yyvsp[(1) - (5)].node), N); (yyval.node)->list = (yyvsp[(3) - (5)].list); @@ -3667,9 +3406,7 @@ yyreduce: break; case 125: - -/* Line 1806 of yacc.c */ -#line 917 "go.y" +#line 918 "go.y" { (yyval.node) = nod(OCALL, (yyvsp[(1) - (6)].node), N); (yyval.node)->list = (yyvsp[(3) - (6)].list); @@ -3678,18 +3415,14 @@ yyreduce: break; case 126: - -/* Line 1806 of yacc.c */ -#line 925 "go.y" +#line 926 "go.y" { (yyval.node) = nodlit((yyvsp[(1) - (1)].val)); } break; case 128: - -/* Line 1806 of yacc.c */ -#line 930 "go.y" +#line 931 "go.y" { if((yyvsp[(1) - (3)].node)->op == OPACK) { Sym *s; @@ -3703,45 +3436,35 @@ yyreduce: break; case 129: - -/* Line 1806 of yacc.c */ -#line 941 "go.y" +#line 942 "go.y" { (yyval.node) = nod(ODOTTYPE, (yyvsp[(1) - (5)].node), (yyvsp[(4) - (5)].node)); } break; case 130: - -/* Line 1806 of yacc.c */ -#line 945 "go.y" +#line 946 "go.y" { (yyval.node) = nod(OTYPESW, N, (yyvsp[(1) - (5)].node)); } break; case 131: - -/* Line 1806 of yacc.c */ -#line 949 "go.y" +#line 950 "go.y" { (yyval.node) = nod(OINDEX, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node)); } break; case 132: - -/* Line 1806 of yacc.c */ -#line 953 "go.y" +#line 954 "go.y" { (yyval.node) = nod(OSLICE, (yyvsp[(1) - (6)].node), nod(OKEY, (yyvsp[(3) - (6)].node), (yyvsp[(5) - (6)].node))); } break; case 133: - -/* Line 1806 of yacc.c */ -#line 957 "go.y" +#line 958 "go.y" { if((yyvsp[(5) - (8)].node) == N) yyerror("middle index required in 3-index slice"); @@ -3752,9 +3475,7 @@ yyreduce: break; case 135: - -/* Line 1806 of yacc.c */ -#line 966 "go.y" +#line 967 "go.y" { // conversion (yyval.node) = nod(OCALL, (yyvsp[(1) - (5)].node), N); @@ -3763,9 +3484,7 @@ yyreduce: break; case 136: - -/* Line 1806 of yacc.c */ -#line 972 "go.y" +#line 973 "go.y" { (yyval.node) = (yyvsp[(3) - (5)].node); (yyval.node)->right = (yyvsp[(1) - (5)].node); @@ -3775,9 +3494,7 @@ yyreduce: break; case 137: - -/* Line 1806 of yacc.c */ -#line 979 "go.y" +#line 980 "go.y" { (yyval.node) = (yyvsp[(3) - (5)].node); (yyval.node)->right = (yyvsp[(1) - (5)].node); @@ -3786,9 +3503,7 @@ yyreduce: break; case 138: - -/* Line 1806 of yacc.c */ -#line 985 "go.y" +#line 986 "go.y" { yyerror("cannot parenthesize type in composite literal"); (yyval.node) = (yyvsp[(5) - (7)].node); @@ -3798,9 +3513,7 @@ yyreduce: break; case 140: - -/* Line 1806 of yacc.c */ -#line 994 "go.y" +#line 995 "go.y" { // composite expression. // make node early so we get the right line number. @@ -3809,18 +3522,14 @@ yyreduce: break; case 141: - -/* Line 1806 of yacc.c */ -#line 1002 "go.y" +#line 1003 "go.y" { (yyval.node) = nod(OKEY, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 142: - -/* Line 1806 of yacc.c */ -#line 1008 "go.y" +#line 1009 "go.y" { // These nodes do not carry line numbers. // Since a composite literal commonly spans several lines, @@ -3840,9 +3549,7 @@ yyreduce: break; case 143: - -/* Line 1806 of yacc.c */ -#line 1025 "go.y" +#line 1026 "go.y" { (yyval.node) = (yyvsp[(2) - (4)].node); (yyval.node)->list = (yyvsp[(3) - (4)].list); @@ -3850,9 +3557,7 @@ yyreduce: break; case 145: - -/* Line 1806 of yacc.c */ -#line 1033 "go.y" +#line 1034 "go.y" { (yyval.node) = (yyvsp[(2) - (4)].node); (yyval.node)->list = (yyvsp[(3) - (4)].list); @@ -3860,9 +3565,7 @@ yyreduce: break; case 147: - -/* Line 1806 of yacc.c */ -#line 1041 "go.y" +#line 1042 "go.y" { (yyval.node) = (yyvsp[(2) - (3)].node); @@ -3882,27 +3585,21 @@ yyreduce: break; case 151: - -/* Line 1806 of yacc.c */ -#line 1067 "go.y" +#line 1068 "go.y" { (yyval.i) = LBODY; } break; case 152: - -/* Line 1806 of yacc.c */ -#line 1071 "go.y" +#line 1072 "go.y" { (yyval.i) = '{'; } break; case 153: - -/* Line 1806 of yacc.c */ -#line 1082 "go.y" +#line 1083 "go.y" { if((yyvsp[(1) - (1)].sym) == S) (yyval.node) = N; @@ -3912,27 +3609,21 @@ yyreduce: break; case 154: - -/* Line 1806 of yacc.c */ -#line 1091 "go.y" +#line 1092 "go.y" { (yyval.node) = dclname((yyvsp[(1) - (1)].sym)); } break; case 155: - -/* Line 1806 of yacc.c */ -#line 1096 "go.y" +#line 1097 "go.y" { (yyval.node) = N; } break; case 157: - -/* Line 1806 of yacc.c */ -#line 1103 "go.y" +#line 1104 "go.y" { (yyval.sym) = (yyvsp[(1) - (1)].sym); // during imports, unqualified non-exported identifiers are from builtinpkg @@ -3942,18 +3633,14 @@ yyreduce: break; case 159: - -/* Line 1806 of yacc.c */ -#line 1111 "go.y" +#line 1112 "go.y" { (yyval.sym) = S; } break; case 160: - -/* Line 1806 of yacc.c */ -#line 1117 "go.y" +#line 1118 "go.y" { Pkg *p; @@ -3969,9 +3656,7 @@ yyreduce: break; case 161: - -/* Line 1806 of yacc.c */ -#line 1130 "go.y" +#line 1131 "go.y" { Pkg *p; @@ -3987,9 +3672,7 @@ yyreduce: break; case 162: - -/* Line 1806 of yacc.c */ -#line 1145 "go.y" +#line 1146 "go.y" { (yyval.node) = oldname((yyvsp[(1) - (1)].sym)); if((yyval.node)->pack != N) @@ -3998,9 +3681,7 @@ yyreduce: break; case 164: - -/* Line 1806 of yacc.c */ -#line 1165 "go.y" +#line 1166 "go.y" { yyerror("final argument in variadic function missing type"); (yyval.node) = nod(ODDD, typenod(typ(TINTER)), N); @@ -4008,45 +3689,35 @@ yyreduce: break; case 165: - -/* Line 1806 of yacc.c */ -#line 1170 "go.y" +#line 1171 "go.y" { (yyval.node) = nod(ODDD, (yyvsp[(2) - (2)].node), N); } break; case 171: - -/* Line 1806 of yacc.c */ -#line 1181 "go.y" +#line 1182 "go.y" { (yyval.node) = nod(OTPAREN, (yyvsp[(2) - (3)].node), N); } break; case 175: - -/* Line 1806 of yacc.c */ -#line 1190 "go.y" +#line 1191 "go.y" { (yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N); } break; case 180: - -/* Line 1806 of yacc.c */ -#line 1200 "go.y" +#line 1201 "go.y" { (yyval.node) = nod(OTPAREN, (yyvsp[(2) - (3)].node), N); } break; case 190: - -/* Line 1806 of yacc.c */ -#line 1221 "go.y" +#line 1222 "go.y" { if((yyvsp[(1) - (3)].node)->op == OPACK) { Sym *s; @@ -4060,18 +3731,14 @@ yyreduce: break; case 191: - -/* Line 1806 of yacc.c */ -#line 1234 "go.y" +#line 1235 "go.y" { (yyval.node) = nod(OTARRAY, (yyvsp[(2) - (4)].node), (yyvsp[(4) - (4)].node)); } break; case 192: - -/* Line 1806 of yacc.c */ -#line 1238 "go.y" +#line 1239 "go.y" { // array literal of nelem (yyval.node) = nod(OTARRAY, nod(ODDD, N, N), (yyvsp[(4) - (4)].node)); @@ -4079,9 +3746,7 @@ yyreduce: break; case 193: - -/* Line 1806 of yacc.c */ -#line 1243 "go.y" +#line 1244 "go.y" { (yyval.node) = nod(OTCHAN, (yyvsp[(2) - (2)].node), N); (yyval.node)->etype = Cboth; @@ -4089,9 +3754,7 @@ yyreduce: break; case 194: - -/* Line 1806 of yacc.c */ -#line 1248 "go.y" +#line 1249 "go.y" { (yyval.node) = nod(OTCHAN, (yyvsp[(3) - (3)].node), N); (yyval.node)->etype = Csend; @@ -4099,27 +3762,21 @@ yyreduce: break; case 195: - -/* Line 1806 of yacc.c */ -#line 1253 "go.y" +#line 1254 "go.y" { (yyval.node) = nod(OTMAP, (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node)); } break; case 198: - -/* Line 1806 of yacc.c */ -#line 1261 "go.y" +#line 1262 "go.y" { (yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N); } break; case 199: - -/* Line 1806 of yacc.c */ -#line 1267 "go.y" +#line 1268 "go.y" { (yyval.node) = nod(OTCHAN, (yyvsp[(3) - (3)].node), N); (yyval.node)->etype = Crecv; @@ -4127,9 +3784,7 @@ yyreduce: break; case 200: - -/* Line 1806 of yacc.c */ -#line 1274 "go.y" +#line 1275 "go.y" { (yyval.node) = nod(OTSTRUCT, N, N); (yyval.node)->list = (yyvsp[(3) - (5)].list); @@ -4138,9 +3793,7 @@ yyreduce: break; case 201: - -/* Line 1806 of yacc.c */ -#line 1280 "go.y" +#line 1281 "go.y" { (yyval.node) = nod(OTSTRUCT, N, N); fixlbrace((yyvsp[(2) - (3)].i)); @@ -4148,9 +3801,7 @@ yyreduce: break; case 202: - -/* Line 1806 of yacc.c */ -#line 1287 "go.y" +#line 1288 "go.y" { (yyval.node) = nod(OTINTER, N, N); (yyval.node)->list = (yyvsp[(3) - (5)].list); @@ -4159,9 +3810,7 @@ yyreduce: break; case 203: - -/* Line 1806 of yacc.c */ -#line 1293 "go.y" +#line 1294 "go.y" { (yyval.node) = nod(OTINTER, N, N); fixlbrace((yyvsp[(2) - (3)].i)); @@ -4169,9 +3818,7 @@ yyreduce: break; case 204: - -/* Line 1806 of yacc.c */ -#line 1304 "go.y" +#line 1305 "go.y" { (yyval.node) = (yyvsp[(2) - (3)].node); if((yyval.node) == N) @@ -4186,9 +3833,7 @@ yyreduce: break; case 205: - -/* Line 1806 of yacc.c */ -#line 1318 "go.y" +#line 1319 "go.y" { Node *t; @@ -4220,9 +3865,7 @@ yyreduce: break; case 206: - -/* Line 1806 of yacc.c */ -#line 1347 "go.y" +#line 1348 "go.y" { Node *rcvr, *t; @@ -4263,9 +3906,7 @@ yyreduce: break; case 207: - -/* Line 1806 of yacc.c */ -#line 1387 "go.y" +#line 1388 "go.y" { Sym *s; Type *t; @@ -4293,9 +3934,7 @@ yyreduce: break; case 208: - -/* Line 1806 of yacc.c */ -#line 1412 "go.y" +#line 1413 "go.y" { (yyval.node) = methodname1(newname((yyvsp[(4) - (8)].sym)), (yyvsp[(2) - (8)].list)->n->right); (yyval.node)->type = functype((yyvsp[(2) - (8)].list)->n, (yyvsp[(6) - (8)].list), (yyvsp[(8) - (8)].list)); @@ -4314,9 +3953,7 @@ yyreduce: break; case 209: - -/* Line 1806 of yacc.c */ -#line 1430 "go.y" +#line 1431 "go.y" { (yyvsp[(3) - (5)].list) = checkarglist((yyvsp[(3) - (5)].list), 1); (yyval.node) = nod(OTFUNC, N, N); @@ -4326,18 +3963,14 @@ yyreduce: break; case 210: - -/* Line 1806 of yacc.c */ -#line 1438 "go.y" +#line 1439 "go.y" { (yyval.list) = nil; } break; case 211: - -/* Line 1806 of yacc.c */ -#line 1442 "go.y" +#line 1443 "go.y" { (yyval.list) = (yyvsp[(2) - (3)].list); if((yyval.list) == nil) @@ -4346,27 +3979,21 @@ yyreduce: break; case 212: - -/* Line 1806 of yacc.c */ -#line 1450 "go.y" +#line 1451 "go.y" { (yyval.list) = nil; } break; case 213: - -/* Line 1806 of yacc.c */ -#line 1454 "go.y" +#line 1455 "go.y" { (yyval.list) = list1(nod(ODCLFIELD, N, (yyvsp[(1) - (1)].node))); } break; case 214: - -/* Line 1806 of yacc.c */ -#line 1458 "go.y" +#line 1459 "go.y" { (yyvsp[(2) - (3)].list) = checkarglist((yyvsp[(2) - (3)].list), 0); (yyval.list) = (yyvsp[(2) - (3)].list); @@ -4374,18 +4001,14 @@ yyreduce: break; case 215: - -/* Line 1806 of yacc.c */ -#line 1465 "go.y" +#line 1466 "go.y" { closurehdr((yyvsp[(1) - (1)].node)); } break; case 216: - -/* Line 1806 of yacc.c */ -#line 1471 "go.y" +#line 1472 "go.y" { (yyval.node) = closurebody((yyvsp[(3) - (4)].list)); fixlbrace((yyvsp[(2) - (4)].i)); @@ -4393,27 +4016,21 @@ yyreduce: break; case 217: - -/* Line 1806 of yacc.c */ -#line 1476 "go.y" +#line 1477 "go.y" { (yyval.node) = closurebody(nil); } break; case 218: - -/* Line 1806 of yacc.c */ -#line 1487 "go.y" +#line 1488 "go.y" { (yyval.list) = nil; } break; case 219: - -/* Line 1806 of yacc.c */ -#line 1491 "go.y" +#line 1492 "go.y" { (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(2) - (3)].list)); if(nsyntaxerrors == 0) @@ -4424,72 +4041,56 @@ yyreduce: break; case 221: - -/* Line 1806 of yacc.c */ -#line 1502 "go.y" +#line 1503 "go.y" { (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); } break; case 223: - -/* Line 1806 of yacc.c */ -#line 1509 "go.y" +#line 1510 "go.y" { (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); } break; case 224: - -/* Line 1806 of yacc.c */ -#line 1515 "go.y" +#line 1516 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 225: - -/* Line 1806 of yacc.c */ -#line 1519 "go.y" +#line 1520 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; case 227: - -/* Line 1806 of yacc.c */ -#line 1526 "go.y" +#line 1527 "go.y" { (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); } break; case 228: - -/* Line 1806 of yacc.c */ -#line 1532 "go.y" +#line 1533 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 229: - -/* Line 1806 of yacc.c */ -#line 1536 "go.y" +#line 1537 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; case 230: - -/* Line 1806 of yacc.c */ -#line 1542 "go.y" +#line 1543 "go.y" { NodeList *l; @@ -4515,9 +4116,7 @@ yyreduce: break; case 231: - -/* Line 1806 of yacc.c */ -#line 1565 "go.y" +#line 1566 "go.y" { (yyvsp[(1) - (2)].node)->val = (yyvsp[(2) - (2)].val); (yyval.list) = list1((yyvsp[(1) - (2)].node)); @@ -4525,9 +4124,7 @@ yyreduce: break; case 232: - -/* Line 1806 of yacc.c */ -#line 1570 "go.y" +#line 1571 "go.y" { (yyvsp[(2) - (4)].node)->val = (yyvsp[(4) - (4)].val); (yyval.list) = list1((yyvsp[(2) - (4)].node)); @@ -4536,9 +4133,7 @@ yyreduce: break; case 233: - -/* Line 1806 of yacc.c */ -#line 1576 "go.y" +#line 1577 "go.y" { (yyvsp[(2) - (3)].node)->right = nod(OIND, (yyvsp[(2) - (3)].node)->right, N); (yyvsp[(2) - (3)].node)->val = (yyvsp[(3) - (3)].val); @@ -4547,9 +4142,7 @@ yyreduce: break; case 234: - -/* Line 1806 of yacc.c */ -#line 1582 "go.y" +#line 1583 "go.y" { (yyvsp[(3) - (5)].node)->right = nod(OIND, (yyvsp[(3) - (5)].node)->right, N); (yyvsp[(3) - (5)].node)->val = (yyvsp[(5) - (5)].val); @@ -4559,9 +4152,7 @@ yyreduce: break; case 235: - -/* Line 1806 of yacc.c */ -#line 1589 "go.y" +#line 1590 "go.y" { (yyvsp[(3) - (5)].node)->right = nod(OIND, (yyvsp[(3) - (5)].node)->right, N); (yyvsp[(3) - (5)].node)->val = (yyvsp[(5) - (5)].val); @@ -4571,9 +4162,7 @@ yyreduce: break; case 236: - -/* Line 1806 of yacc.c */ -#line 1598 "go.y" +#line 1599 "go.y" { Node *n; @@ -4585,9 +4174,7 @@ yyreduce: break; case 237: - -/* Line 1806 of yacc.c */ -#line 1607 "go.y" +#line 1608 "go.y" { Pkg *pkg; @@ -4603,18 +4190,14 @@ yyreduce: break; case 238: - -/* Line 1806 of yacc.c */ -#line 1622 "go.y" +#line 1623 "go.y" { (yyval.node) = embedded((yyvsp[(1) - (1)].sym), localpkg); } break; case 239: - -/* Line 1806 of yacc.c */ -#line 1628 "go.y" +#line 1629 "go.y" { (yyval.node) = nod(ODCLFIELD, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node)); ifacedcl((yyval.node)); @@ -4622,18 +4205,14 @@ yyreduce: break; case 240: - -/* Line 1806 of yacc.c */ -#line 1633 "go.y" +#line 1634 "go.y" { (yyval.node) = nod(ODCLFIELD, N, oldname((yyvsp[(1) - (1)].sym))); } break; case 241: - -/* Line 1806 of yacc.c */ -#line 1637 "go.y" +#line 1638 "go.y" { (yyval.node) = nod(ODCLFIELD, N, oldname((yyvsp[(2) - (3)].sym))); yyerror("cannot parenthesize embedded type"); @@ -4641,9 +4220,7 @@ yyreduce: break; case 242: - -/* Line 1806 of yacc.c */ -#line 1644 "go.y" +#line 1645 "go.y" { // without func keyword (yyvsp[(2) - (4)].list) = checkarglist((yyvsp[(2) - (4)].list), 1); @@ -4654,9 +4231,7 @@ yyreduce: break; case 244: - -/* Line 1806 of yacc.c */ -#line 1658 "go.y" +#line 1659 "go.y" { (yyval.node) = nod(ONONAME, N, N); (yyval.node)->sym = (yyvsp[(1) - (2)].sym); @@ -4665,9 +4240,7 @@ yyreduce: break; case 245: - -/* Line 1806 of yacc.c */ -#line 1664 "go.y" +#line 1665 "go.y" { (yyval.node) = nod(ONONAME, N, N); (yyval.node)->sym = (yyvsp[(1) - (2)].sym); @@ -4676,72 +4249,56 @@ yyreduce: break; case 247: - -/* Line 1806 of yacc.c */ -#line 1673 "go.y" +#line 1674 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 248: - -/* Line 1806 of yacc.c */ -#line 1677 "go.y" +#line 1678 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; case 249: - -/* Line 1806 of yacc.c */ -#line 1682 "go.y" +#line 1683 "go.y" { (yyval.list) = nil; } break; case 250: - -/* Line 1806 of yacc.c */ -#line 1686 "go.y" +#line 1687 "go.y" { (yyval.list) = (yyvsp[(1) - (2)].list); } break; case 251: - -/* Line 1806 of yacc.c */ -#line 1694 "go.y" +#line 1695 "go.y" { (yyval.node) = N; } break; case 253: - -/* Line 1806 of yacc.c */ -#line 1699 "go.y" +#line 1700 "go.y" { (yyval.node) = liststmt((yyvsp[(1) - (1)].list)); } break; case 255: - -/* Line 1806 of yacc.c */ -#line 1704 "go.y" +#line 1705 "go.y" { (yyval.node) = N; } break; case 261: - -/* Line 1806 of yacc.c */ -#line 1715 "go.y" +#line 1716 "go.y" { (yyvsp[(1) - (2)].node) = nod(OLABEL, (yyvsp[(1) - (2)].node), N); (yyvsp[(1) - (2)].node)->sym = dclstack; // context, for goto restrictions @@ -4749,9 +4306,7 @@ yyreduce: break; case 262: - -/* Line 1806 of yacc.c */ -#line 1720 "go.y" +#line 1721 "go.y" { NodeList *l; @@ -4764,55 +4319,44 @@ yyreduce: break; case 263: - -/* Line 1806 of yacc.c */ -#line 1730 "go.y" +#line 1731 "go.y" { // will be converted to OFALL (yyval.node) = nod(OXFALL, N, N); + (yyval.node)->xoffset = block; } break; case 264: - -/* Line 1806 of yacc.c */ -#line 1735 "go.y" +#line 1737 "go.y" { (yyval.node) = nod(OBREAK, (yyvsp[(2) - (2)].node), N); } break; case 265: - -/* Line 1806 of yacc.c */ -#line 1739 "go.y" +#line 1741 "go.y" { (yyval.node) = nod(OCONTINUE, (yyvsp[(2) - (2)].node), N); } break; case 266: - -/* Line 1806 of yacc.c */ -#line 1743 "go.y" +#line 1745 "go.y" { (yyval.node) = nod(OPROC, (yyvsp[(2) - (2)].node), N); } break; case 267: - -/* Line 1806 of yacc.c */ -#line 1747 "go.y" +#line 1749 "go.y" { (yyval.node) = nod(ODEFER, (yyvsp[(2) - (2)].node), N); } break; case 268: - -/* Line 1806 of yacc.c */ -#line 1751 "go.y" +#line 1753 "go.y" { (yyval.node) = nod(OGOTO, (yyvsp[(2) - (2)].node), N); (yyval.node)->sym = dclstack; // context, for goto restrictions @@ -4820,9 +4364,7 @@ yyreduce: break; case 269: - -/* Line 1806 of yacc.c */ -#line 1756 "go.y" +#line 1758 "go.y" { (yyval.node) = nod(ORETURN, N, N); (yyval.node)->list = (yyvsp[(2) - (2)].list); @@ -4842,9 +4384,7 @@ yyreduce: break; case 270: - -/* Line 1806 of yacc.c */ -#line 1775 "go.y" +#line 1777 "go.y" { (yyval.list) = nil; if((yyvsp[(1) - (1)].node) != N) @@ -4853,9 +4393,7 @@ yyreduce: break; case 271: - -/* Line 1806 of yacc.c */ -#line 1781 "go.y" +#line 1783 "go.y" { (yyval.list) = (yyvsp[(1) - (3)].list); if((yyvsp[(3) - (3)].node) != N) @@ -4864,243 +4402,189 @@ yyreduce: break; case 272: - -/* Line 1806 of yacc.c */ -#line 1789 "go.y" +#line 1791 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 273: - -/* Line 1806 of yacc.c */ -#line 1793 "go.y" +#line 1795 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; case 274: - -/* Line 1806 of yacc.c */ -#line 1799 "go.y" +#line 1801 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 275: - -/* Line 1806 of yacc.c */ -#line 1803 "go.y" +#line 1805 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; case 276: - -/* Line 1806 of yacc.c */ -#line 1809 "go.y" +#line 1811 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 277: - -/* Line 1806 of yacc.c */ -#line 1813 "go.y" +#line 1815 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; case 278: - -/* Line 1806 of yacc.c */ -#line 1819 "go.y" +#line 1821 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 279: - -/* Line 1806 of yacc.c */ -#line 1823 "go.y" +#line 1825 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; case 280: - -/* Line 1806 of yacc.c */ -#line 1832 "go.y" +#line 1834 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 281: - -/* Line 1806 of yacc.c */ -#line 1836 "go.y" +#line 1838 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 282: - -/* Line 1806 of yacc.c */ -#line 1840 "go.y" +#line 1842 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; case 283: - -/* Line 1806 of yacc.c */ -#line 1844 "go.y" +#line 1846 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; case 284: - -/* Line 1806 of yacc.c */ -#line 1849 "go.y" +#line 1851 "go.y" { (yyval.list) = nil; } break; case 285: - -/* Line 1806 of yacc.c */ -#line 1853 "go.y" +#line 1855 "go.y" { (yyval.list) = (yyvsp[(1) - (2)].list); } break; case 290: - -/* Line 1806 of yacc.c */ -#line 1867 "go.y" +#line 1869 "go.y" { (yyval.node) = N; } break; case 292: - -/* Line 1806 of yacc.c */ -#line 1873 "go.y" +#line 1875 "go.y" { (yyval.list) = nil; } break; case 294: - -/* Line 1806 of yacc.c */ -#line 1879 "go.y" +#line 1881 "go.y" { (yyval.node) = N; } break; case 296: - -/* Line 1806 of yacc.c */ -#line 1885 "go.y" +#line 1887 "go.y" { (yyval.list) = nil; } break; case 298: - -/* Line 1806 of yacc.c */ -#line 1891 "go.y" +#line 1893 "go.y" { (yyval.list) = nil; } break; case 300: - -/* Line 1806 of yacc.c */ -#line 1897 "go.y" +#line 1899 "go.y" { (yyval.list) = nil; } break; case 302: - -/* Line 1806 of yacc.c */ -#line 1903 "go.y" +#line 1905 "go.y" { (yyval.val).ctype = CTxxx; } break; case 304: - -/* Line 1806 of yacc.c */ -#line 1913 "go.y" +#line 1915 "go.y" { importimport((yyvsp[(2) - (4)].sym), (yyvsp[(3) - (4)].val).u.sval); } break; case 305: - -/* Line 1806 of yacc.c */ -#line 1917 "go.y" +#line 1919 "go.y" { importvar((yyvsp[(2) - (4)].sym), (yyvsp[(3) - (4)].type)); } break; case 306: - -/* Line 1806 of yacc.c */ -#line 1921 "go.y" +#line 1923 "go.y" { importconst((yyvsp[(2) - (5)].sym), types[TIDEAL], (yyvsp[(4) - (5)].node)); } break; case 307: - -/* Line 1806 of yacc.c */ -#line 1925 "go.y" +#line 1927 "go.y" { importconst((yyvsp[(2) - (6)].sym), (yyvsp[(3) - (6)].type), (yyvsp[(5) - (6)].node)); } break; case 308: - -/* Line 1806 of yacc.c */ -#line 1929 "go.y" +#line 1931 "go.y" { importtype((yyvsp[(2) - (4)].type), (yyvsp[(3) - (4)].type)); } break; case 309: - -/* Line 1806 of yacc.c */ -#line 1933 "go.y" +#line 1935 "go.y" { if((yyvsp[(2) - (4)].node) == N) { dclcontext = PEXTERN; // since we skip the funcbody below @@ -5121,9 +4605,7 @@ yyreduce: break; case 310: - -/* Line 1806 of yacc.c */ -#line 1953 "go.y" +#line 1955 "go.y" { (yyval.sym) = (yyvsp[(1) - (1)].sym); structpkg = (yyval.sym)->pkg; @@ -5131,9 +4613,7 @@ yyreduce: break; case 311: - -/* Line 1806 of yacc.c */ -#line 1960 "go.y" +#line 1962 "go.y" { (yyval.type) = pkgtype((yyvsp[(1) - (1)].sym)); importsym((yyvsp[(1) - (1)].sym), OTYPE); @@ -5141,18 +4621,14 @@ yyreduce: break; case 317: - -/* Line 1806 of yacc.c */ -#line 1980 "go.y" +#line 1982 "go.y" { (yyval.type) = pkgtype((yyvsp[(1) - (1)].sym)); } break; case 318: - -/* Line 1806 of yacc.c */ -#line 1984 "go.y" +#line 1986 "go.y" { // predefined name like uint8 (yyvsp[(1) - (1)].sym) = pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg); @@ -5165,63 +4641,49 @@ yyreduce: break; case 319: - -/* Line 1806 of yacc.c */ -#line 1994 "go.y" +#line 1996 "go.y" { (yyval.type) = aindex(N, (yyvsp[(3) - (3)].type)); } break; case 320: - -/* Line 1806 of yacc.c */ -#line 1998 "go.y" +#line 2000 "go.y" { (yyval.type) = aindex(nodlit((yyvsp[(2) - (4)].val)), (yyvsp[(4) - (4)].type)); } break; case 321: - -/* Line 1806 of yacc.c */ -#line 2002 "go.y" +#line 2004 "go.y" { (yyval.type) = maptype((yyvsp[(3) - (5)].type), (yyvsp[(5) - (5)].type)); } break; case 322: - -/* Line 1806 of yacc.c */ -#line 2006 "go.y" +#line 2008 "go.y" { (yyval.type) = tostruct((yyvsp[(3) - (4)].list)); } break; case 323: - -/* Line 1806 of yacc.c */ -#line 2010 "go.y" +#line 2012 "go.y" { (yyval.type) = tointerface((yyvsp[(3) - (4)].list)); } break; case 324: - -/* Line 1806 of yacc.c */ -#line 2014 "go.y" +#line 2016 "go.y" { (yyval.type) = ptrto((yyvsp[(2) - (2)].type)); } break; case 325: - -/* Line 1806 of yacc.c */ -#line 2018 "go.y" +#line 2020 "go.y" { (yyval.type) = typ(TCHAN); (yyval.type)->type = (yyvsp[(2) - (2)].type); @@ -5230,9 +4692,7 @@ yyreduce: break; case 326: - -/* Line 1806 of yacc.c */ -#line 2024 "go.y" +#line 2026 "go.y" { (yyval.type) = typ(TCHAN); (yyval.type)->type = (yyvsp[(3) - (4)].type); @@ -5241,9 +4701,7 @@ yyreduce: break; case 327: - -/* Line 1806 of yacc.c */ -#line 2030 "go.y" +#line 2032 "go.y" { (yyval.type) = typ(TCHAN); (yyval.type)->type = (yyvsp[(3) - (3)].type); @@ -5252,9 +4710,7 @@ yyreduce: break; case 328: - -/* Line 1806 of yacc.c */ -#line 2038 "go.y" +#line 2040 "go.y" { (yyval.type) = typ(TCHAN); (yyval.type)->type = (yyvsp[(3) - (3)].type); @@ -5263,18 +4719,14 @@ yyreduce: break; case 329: - -/* Line 1806 of yacc.c */ -#line 2046 "go.y" +#line 2048 "go.y" { (yyval.type) = functype(nil, (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list)); } break; case 330: - -/* Line 1806 of yacc.c */ -#line 2052 "go.y" +#line 2054 "go.y" { (yyval.node) = nod(ODCLFIELD, N, typenod((yyvsp[(2) - (3)].type))); if((yyvsp[(1) - (3)].sym)) @@ -5284,9 +4736,7 @@ yyreduce: break; case 331: - -/* Line 1806 of yacc.c */ -#line 2059 "go.y" +#line 2061 "go.y" { Type *t; @@ -5303,9 +4753,7 @@ yyreduce: break; case 332: - -/* Line 1806 of yacc.c */ -#line 2075 "go.y" +#line 2077 "go.y" { Sym *s; Pkg *p; @@ -5328,63 +4776,49 @@ yyreduce: break; case 333: - -/* Line 1806 of yacc.c */ -#line 2097 "go.y" +#line 2099 "go.y" { (yyval.node) = nod(ODCLFIELD, newname((yyvsp[(1) - (5)].sym)), typenod(functype(fakethis(), (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list)))); } break; case 334: - -/* Line 1806 of yacc.c */ -#line 2101 "go.y" +#line 2103 "go.y" { (yyval.node) = nod(ODCLFIELD, N, typenod((yyvsp[(1) - (1)].type))); } break; case 335: - -/* Line 1806 of yacc.c */ -#line 2106 "go.y" +#line 2108 "go.y" { (yyval.list) = nil; } break; case 337: - -/* Line 1806 of yacc.c */ -#line 2113 "go.y" +#line 2115 "go.y" { (yyval.list) = (yyvsp[(2) - (3)].list); } break; case 338: - -/* Line 1806 of yacc.c */ -#line 2117 "go.y" +#line 2119 "go.y" { (yyval.list) = list1(nod(ODCLFIELD, N, typenod((yyvsp[(1) - (1)].type)))); } break; case 339: - -/* Line 1806 of yacc.c */ -#line 2127 "go.y" +#line 2129 "go.y" { (yyval.node) = nodlit((yyvsp[(1) - (1)].val)); } break; case 340: - -/* Line 1806 of yacc.c */ -#line 2131 "go.y" +#line 2133 "go.y" { (yyval.node) = nodlit((yyvsp[(2) - (2)].val)); switch((yyval.node)->val.ctype){ @@ -5395,6 +4829,10 @@ yyreduce: case CTFLT: mpnegflt((yyval.node)->val.u.fval); break; + case CTCPLX: + mpnegflt(&(yyval.node)->val.u.cval->real); + mpnegflt(&(yyval.node)->val.u.cval->imag); + break; default: yyerror("bad negated constant"); } @@ -5402,9 +4840,7 @@ yyreduce: break; case 341: - -/* Line 1806 of yacc.c */ -#line 2146 "go.y" +#line 2152 "go.y" { (yyval.node) = oldname(pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg)); if((yyval.node)->op != OLITERAL) @@ -5413,9 +4849,7 @@ yyreduce: break; case 343: - -/* Line 1806 of yacc.c */ -#line 2155 "go.y" +#line 2161 "go.y" { if((yyvsp[(2) - (5)].node)->val.ctype == CTRUNE && (yyvsp[(4) - (5)].node)->val.ctype == CTINT) { (yyval.node) = (yyvsp[(2) - (5)].node); @@ -5429,76 +4863,52 @@ yyreduce: break; case 346: - -/* Line 1806 of yacc.c */ -#line 2171 "go.y" +#line 2177 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 347: - -/* Line 1806 of yacc.c */ -#line 2175 "go.y" +#line 2181 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; case 348: - -/* Line 1806 of yacc.c */ -#line 2181 "go.y" +#line 2187 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 349: - -/* Line 1806 of yacc.c */ -#line 2185 "go.y" +#line 2191 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; case 350: - -/* Line 1806 of yacc.c */ -#line 2191 "go.y" +#line 2197 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 351: - -/* Line 1806 of yacc.c */ -#line 2195 "go.y" +#line 2201 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; - -/* Line 1806 of yacc.c */ -#line 5490 "y.tab.c" +/* Line 1267 of yacc.c. */ +#line 4911 "y.tab.c" default: break; } - /* User semantic actions sometimes alter yychar, and that requires - that yytoken be updated with the new translation. We take the - approach of translating immediately before every use of yytoken. - One alternative is translating here after every semantic action, - but that translation would be missed if the semantic action invokes - YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or - if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an - incorrect destructor might then be invoked immediately. In the - case of YYERROR or YYBACKUP, subsequent parser actions might lead - to an incorrect destructor call or verbose syntax error message - before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); YYPOPSTACK (yylen); @@ -5507,6 +4917,7 @@ yyreduce: *++yyvsp = yyval; + /* Now `shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ @@ -5526,10 +4937,6 @@ yyreduce: | yyerrlab -- here on detecting error | `------------------------------------*/ yyerrlab: - /* Make sure we have latest lookahead translation. See comments at - user semantic actions for why this is necessary. */ - yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); - /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { @@ -5537,36 +4944,37 @@ yyerrlab: #if ! YYERROR_VERBOSE yyerror (YY_("syntax error")); #else -# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ - yyssp, yytoken) { - char *yymsgp = YY_("syntax error"); - int yysyntax_error_status; - yysyntax_error_status = YYSYNTAX_ERROR; - if (yysyntax_error_status == 0) - yymsgp = yymsg; - else if (yysyntax_error_status == 1) - { - if (yymsg != yymsgbuf) - YYSTACK_FREE (yymsg); - yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); - if (!yymsg) - { - yymsg = yymsgbuf; - yymsg_alloc = sizeof yymsgbuf; - yysyntax_error_status = 2; - } - else - { - yysyntax_error_status = YYSYNTAX_ERROR; - yymsgp = yymsg; - } - } - yyerror (yymsgp); - if (yysyntax_error_status == 2) - goto yyexhaustedlab; + YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); + if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) + { + YYSIZE_T yyalloc = 2 * yysize; + if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) + yyalloc = YYSTACK_ALLOC_MAXIMUM; + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yyalloc); + if (yymsg) + yymsg_alloc = yyalloc; + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + } + } + + if (0 < yysize && yysize <= yymsg_alloc) + { + (void) yysyntax_error (yymsg, yystate, yychar); + yyerror (yymsg); + } + else + { + yyerror (YY_("syntax error")); + if (yysize != 0) + goto yyexhaustedlab; + } } -# undef YYSYNTAX_ERROR #endif } @@ -5574,7 +4982,7 @@ yyerrlab: if (yyerrstatus == 3) { - /* If just tried and failed to reuse lookahead token after an + /* If just tried and failed to reuse look-ahead token after an error, discard it. */ if (yychar <= YYEOF) @@ -5591,7 +4999,7 @@ yyerrlab: } } - /* Else will try to reuse lookahead token after shifting the error + /* Else will try to reuse look-ahead token after shifting the error token. */ goto yyerrlab1; @@ -5625,7 +5033,7 @@ yyerrlab1: for (;;) { yyn = yypact[yystate]; - if (!yypact_value_is_default (yyn)) + if (yyn != YYPACT_NINF) { yyn += YYTERROR; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) @@ -5648,6 +5056,9 @@ yyerrlab1: YY_STACK_PRINT (yyss, yyssp); } + if (yyn == YYFINAL) + YYACCEPT; + *++yyvsp = yylval; @@ -5672,7 +5083,7 @@ yyabortlab: yyresult = 1; goto yyreturn; -#if !defined(yyoverflow) || YYERROR_VERBOSE +#ifndef yyoverflow /*-------------------------------------------------. | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ @@ -5683,14 +5094,9 @@ yyexhaustedlab: #endif yyreturn: - if (yychar != YYEMPTY) - { - /* Make sure we have latest lookahead translation. See comments at - user semantic actions for why this is necessary. */ - yytoken = YYTRANSLATE (yychar); - yydestruct ("Cleanup: discarding lookahead", - yytoken, &yylval); - } + if (yychar != YYEOF && yychar != YYEMPTY) + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); /* Do not reclaim the symbols of the rule which action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); @@ -5714,9 +5120,7 @@ yyreturn: } - -/* Line 2067 of yacc.c */ -#line 2199 "go.y" +#line 2205 "go.y" static void diff --git a/src/cmd/gc/y.tab.h b/src/cmd/gc/y.tab.h index 6eeb831b2..d01fbe198 100644 --- a/src/cmd/gc/y.tab.h +++ b/src/cmd/gc/y.tab.h @@ -1,21 +1,24 @@ -/* A Bison parser, made by GNU Bison 2.5. */ +/* A Bison parser, made by GNU Bison 2.3. */ -/* Bison interface for Yacc-like parsers in C - - Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify +/* Skeleton interface for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - + the Free Software Foundation; either version 2, or (at your option) + any later version. + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License - along with this program. If not, see . */ + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work @@ -26,11 +29,10 @@ special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. - + This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ - /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE @@ -144,28 +146,22 @@ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE -{ - -/* Line 2068 of yacc.c */ #line 28 "go.y" - +{ Node* node; NodeList* list; Type* type; Sym* sym; struct Val val; int i; - - - -/* Line 2068 of yacc.c */ -#line 163 "y.tab.h" -} YYSTYPE; -# define YYSTYPE_IS_TRIVIAL 1 +} +/* Line 1529 of yacc.c. */ +#line 160 "y.tab.h" + YYSTYPE; # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 #endif extern YYSTYPE yylval; - diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go index f70f778d9..3645f1c2d 100644 --- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -5,6 +5,7 @@ package main import ( + "bufio" "bytes" "container/heap" "errors" @@ -27,7 +28,7 @@ import ( ) var cmdBuild = &Command{ - UsageLine: "build [-o output] [build flags] [packages]", + UsageLine: "build [-o output] [-i] [build flags] [packages]", Short: "compile packages and dependencies", Long: ` Build compiles the packages named by the import paths, @@ -49,7 +50,10 @@ derives from the first file name mentioned, such as f1 for 'go build f1.go f2.go'; with no files provided ('go build'), the output file name is the base name of the containing directory. -The build flags are shared by the build, install, run, and test commands: +The -i flag installs the packages that are dependencies of the target. + +The build flags are shared by the build, clean, get, install, list, run, +and test commands: -a force rebuilding of packages that are already up-to-date. @@ -86,8 +90,8 @@ The build flags are shared by the build, install, run, and test commands: arguments to pass on each 5l, 6l, or 8l linker invocation. -tags 'tag list' a list of build tags to consider satisfied during the build. - See the documentation for the go/build package for - more information about build tags. + For more information about build tags, see the description of + build constraints in the documentation for the go/build package. The list flags accept a space-separated list of strings. To embed spaces in an element in the list, surround it with either single or double quotes. @@ -106,6 +110,8 @@ func init() { cmdBuild.Run = runBuild cmdInstall.Run = runInstall + cmdBuild.Flag.BoolVar(&buildI, "i", false, "") + addBuildFlags(cmdBuild) addBuildFlags(cmdInstall) } @@ -116,6 +122,7 @@ var buildN bool // -n flag var buildP = runtime.NumCPU() // -p flag var buildV bool // -v flag var buildX bool // -x flag +var buildI bool // -i flag var buildO = cmdBuild.Flag.String("o", "", "output file") var buildWork bool // -work flag var buildGcflags []string // -gcflags flag @@ -158,7 +165,8 @@ func init() { } } -// addBuildFlags adds the flags common to the build and install commands. +// addBuildFlags adds the flags common to the build, clean, get, +// install, list, run, and test commands. func addBuildFlags(cmd *Command) { // NOTE: If you add flags here, also add them to testflag.go. cmd.Flag.BoolVar(&buildA, "a", false, "") @@ -203,6 +211,9 @@ type stringsFlag []string func (v *stringsFlag) Set(s string) error { var err error *v, err = splitQuotedFields(s) + if *v == nil { + *v = []string{} + } return err } @@ -286,8 +297,12 @@ func runBuild(cmd *Command, args []string) { } a := &action{} + depMode := modeBuild + if buildI { + depMode = modeInstall + } for _, p := range packages(args) { - a.deps = append(a.deps, b.action(modeBuild, modeBuild, p)) + a.deps = append(a.deps, b.action(modeBuild, depMode, p)) } b.do(a) } @@ -349,7 +364,12 @@ func init() { var err error archChar, err = build.ArchChar(goarch) if err != nil { - fatalf("%s", err) + if _, isgc := buildToolchain.(gcToolchain); isgc { + fatalf("%s", err) + } + // archChar is only required for gcToolchain, if we're using + // another toolchain leave it blank. + archChar = "" } } @@ -438,7 +458,8 @@ func (b *builder) init() { fmt.Fprintf(os.Stderr, "WORK=%s\n", b.work) } if !buildWork { - atexit(func() { os.RemoveAll(b.work) }) + workdir := b.work + atexit(func() { os.RemoveAll(workdir) }) } } } @@ -760,6 +781,11 @@ func (b *builder) build(a *action) (err error) { return fmt.Errorf("can't build package %s because it contains C++ files (%s) but it's not using cgo nor SWIG", a.p.ImportPath, strings.Join(a.p.CXXFiles, ",")) } + // Same as above for Objective-C files + if len(a.p.MFiles) > 0 && !a.p.usesCgo() && !a.p.usesSwig() { + return fmt.Errorf("can't build package %s because it contains Objective-C files (%s) but it's not using cgo nor SWIG", + a.p.ImportPath, strings.Join(a.p.MFiles, ",")) + } defer func() { if err != nil && err != errPrintedOutput { err = fmt.Errorf("go build %s: %v", a.p.ImportPath, err) @@ -799,25 +825,7 @@ func (b *builder) build(a *action) (err error) { var gofiles, cfiles, sfiles, objects, cgoObjects []string - // If we're doing coverage, preprocess the .go files and put them in the work directory - if a.p.coverMode != "" { - for _, file := range a.p.GoFiles { - sourceFile := filepath.Join(a.p.Dir, file) - cover := a.p.coverVars[file] - if cover == nil || isTestFile(file) { - // Not covering this file. - gofiles = append(gofiles, file) - continue - } - coverFile := filepath.Join(obj, file) - if err := b.cover(a, coverFile, sourceFile, 0666, cover.Var); err != nil { - return err - } - gofiles = append(gofiles, coverFile) - } - } else { - gofiles = append(gofiles, a.p.GoFiles...) - } + gofiles = append(gofiles, a.p.GoFiles...) cfiles = append(cfiles, a.p.CFiles...) sfiles = append(sfiles, a.p.SFiles...) @@ -851,7 +859,7 @@ func (b *builder) build(a *action) (err error) { if a.cgo != nil && a.cgo.target != "" { cgoExe = a.cgo.target } - outGo, outObj, err := b.cgo(a.p, cgoExe, obj, gccfiles, a.p.CXXFiles) + outGo, outObj, err := b.cgo(a.p, cgoExe, obj, gccfiles, a.p.CXXFiles, a.p.MFiles) if err != nil { return err } @@ -866,7 +874,7 @@ func (b *builder) build(a *action) (err error) { gccfiles := append(cfiles, sfiles...) cfiles = nil sfiles = nil - outGo, outObj, err := b.swig(a.p, obj, gccfiles, a.p.CXXFiles) + outGo, outObj, err := b.swig(a.p, obj, gccfiles, a.p.CXXFiles, a.p.MFiles) if err != nil { return err } @@ -874,21 +882,54 @@ func (b *builder) build(a *action) (err error) { gofiles = append(gofiles, outGo...) } + if len(gofiles) == 0 { + return &build.NoGoError{a.p.Dir} + } + + // If we're doing coverage, preprocess the .go files and put them in the work directory + if a.p.coverMode != "" { + for i, file := range gofiles { + var sourceFile string + var coverFile string + var key string + if strings.HasSuffix(file, ".cgo1.go") { + // cgo files have absolute paths + base := filepath.Base(file) + sourceFile = file + coverFile = filepath.Join(obj, base) + key = strings.TrimSuffix(base, ".cgo1.go") + ".go" + } else { + sourceFile = filepath.Join(a.p.Dir, file) + coverFile = filepath.Join(obj, file) + key = file + } + cover := a.p.coverVars[key] + if cover == nil || isTestFile(file) { + // Not covering this file. + continue + } + if err := b.cover(a, coverFile, sourceFile, 0666, cover.Var); err != nil { + return err + } + gofiles[i] = coverFile + } + } + // Prepare Go import path list. inc := b.includeArgs("-I", a.deps) // Compile Go. - if len(gofiles) > 0 { - ofile, out, err := buildToolchain.gc(b, a.p, obj, inc, gofiles) - if len(out) > 0 { - b.showOutput(a.p.Dir, a.p.ImportPath, b.processOutput(out)) - if err != nil { - return errPrintedOutput - } - } + ofile, out, err := buildToolchain.gc(b, a.p, a.objpkg, obj, inc, gofiles) + if len(out) > 0 { + b.showOutput(a.p.Dir, a.p.ImportPath, b.processOutput(out)) if err != nil { - return err + return errPrintedOutput } + } + if err != nil { + return err + } + if ofile != a.objpkg { objects = append(objects, ofile) } @@ -903,17 +944,17 @@ func (b *builder) build(a *action) (err error) { switch { case strings.HasSuffix(name, _goos_goarch): targ := file[:len(name)-len(_goos_goarch)] + "_GOOS_GOARCH." + ext - if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0666); err != nil { + if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0644); err != nil { return err } case strings.HasSuffix(name, _goarch): targ := file[:len(name)-len(_goarch)] + "_GOARCH." + ext - if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0666); err != nil { + if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0644); err != nil { return err } case strings.HasSuffix(name, _goos): targ := file[:len(name)-len(_goos)] + "_GOOS." + ext - if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0666); err != nil { + if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0644); err != nil { return err } } @@ -952,9 +993,15 @@ func (b *builder) build(a *action) (err error) { objects = append(objects, filepath.Join(a.p.Dir, syso)) } - // Pack into archive in obj directory - if err := buildToolchain.pack(b, a.p, obj, a.objpkg, objects); err != nil { - return err + // Pack into archive in obj directory. + // If the Go compiler wrote an archive, we only need to add the + // object files for non-Go sources to the archive. + // If the Go compiler wrote an archive and the package is entirely + // Go sources, there is no pack to execute at all. + if len(objects) > 0 { + if err := buildToolchain.pack(b, a.p, obj, a.objpkg, objects); err != nil { + return err + } } // Link if needed. @@ -979,9 +1026,9 @@ func (b *builder) install(a *action) (err error) { } }() a1 := a.deps[0] - perm := os.FileMode(0666) + perm := os.FileMode(0644) if a1.link { - perm = 0777 + perm = 0755 } // make target directory @@ -1001,22 +1048,7 @@ func (b *builder) install(a *action) (err error) { defer os.Remove(a1.target) } - if a.p.usesSwig() { - for _, f := range stringList(a.p.SwigFiles, a.p.SwigCXXFiles) { - dir = a.p.swigDir(&buildContext) - if err := b.mkdir(dir); err != nil { - return err - } - soname := a.p.swigSoname(f) - source := filepath.Join(a.objdir, soname) - target := filepath.Join(dir, soname) - if err = b.copyFile(a, target, source, perm); err != nil { - return err - } - } - } - - return b.copyFile(a, a.target, a1.target, perm) + return b.moveOrCopyFile(a, a.target, a1.target, perm) } // includeArgs returns the -I or -L directory list for access @@ -1062,6 +1094,27 @@ func (b *builder) includeArgs(flag string, all []*action) []string { return inc } +// moveOrCopyFile is like 'mv src dst' or 'cp src dst'. +func (b *builder) moveOrCopyFile(a *action, dst, src string, perm os.FileMode) error { + if buildN { + b.showcmd("", "mv %s %s", src, dst) + return nil + } + + // If we can update the mode and rename to the dst, do it. + // Otherwise fall back to standard copy. + if err := os.Chmod(src, perm); err == nil { + if err := os.Rename(src, dst); err == nil { + if buildX { + b.showcmd("", "mv %s %s", src, dst) + } + return nil + } + } + + return b.copyFile(a, dst, src, perm) +} + // copyFile is like 'cp src dst'. func (b *builder) copyFile(a *action, dst, src string, perm os.FileMode) error { if buildN || buildX { @@ -1262,6 +1315,7 @@ func relPaths(paths []string) []string { var errPrintedOutput = errors.New("already printed output - no need to show error") var cgoLine = regexp.MustCompile(`\[[^\[\]]+\.cgo1\.go:[0-9]+\]`) +var cgoTypeSigRe = regexp.MustCompile(`\b_Ctype_\B`) // run runs the command given by cmdline in the directory dir. // If the command fails, run prints information about the failure @@ -1288,11 +1342,11 @@ func (b *builder) processOutput(out []byte) string { messages := string(out) // Fix up output referring to cgo-generated code to be more readable. // Replace x.go:19[/tmp/.../x.cgo1.go:18] with x.go:19. - // Replace _Ctype_foo with C.foo. + // Replace *[100]_Ctype_foo with *[100]C.foo. // If we're using -x, assume we're debugging and want the full dump, so disable the rewrite. if !buildX && cgoLine.MatchString(messages) { messages = cgoLine.ReplaceAllString(messages, "") - messages = strings.Replace(messages, "type _Ctype_", "type C.", -1) + messages = cgoTypeSigRe.ReplaceAllString(messages, "C.") } return messages } @@ -1302,7 +1356,13 @@ func (b *builder) processOutput(out []byte) string { func (b *builder) runOut(dir string, desc string, env []string, cmdargs ...interface{}) ([]byte, error) { cmdline := stringList(cmdargs...) if buildN || buildX { - b.showcmd(dir, "%s", joinUnambiguously(cmdline)) + var envcmdline string + for i := range env { + envcmdline += env[i] + envcmdline += " " + } + envcmdline += joinUnambiguously(cmdline) + b.showcmd(dir, "%s", envcmdline) if buildN { return nil, nil } @@ -1432,7 +1492,7 @@ type toolchain interface { // gc runs the compiler in a specific directory on a set of files // and returns the name of the generated output file. // The compiler runs in the directory dir. - gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, out []byte, err error) + gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, out []byte, err error) // cc runs the toolchain's C compiler in a directory on a C file // to produce an output file. cc(b *builder, p *Package, objdir, ofile, cfile string) error @@ -1469,7 +1529,7 @@ func (noToolchain) linker() string { return "" } -func (noToolchain) gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, out []byte, err error) { +func (noToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, out []byte, err error) { return "", nil, noCompiler() } @@ -1505,9 +1565,14 @@ func (gcToolchain) linker() string { return tool(archChar + "l") } -func (gcToolchain) gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, output []byte, err error) { - out := "_go_." + archChar - ofile = obj + out +func (gcToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, output []byte, err error) { + if archive != "" { + ofile = archive + } else { + out := "_go_." + archChar + ofile = obj + out + } + gcargs := []string{"-p", p.ImportPath} if p.Standard && p.ImportPath == "runtime" { // runtime compiles with a special 6g flag to emit @@ -1519,7 +1584,7 @@ func (gcToolchain) gc(b *builder, p *Package, obj string, importArgs []string, g // so that it can give good error messages about forward declarations. // Exceptions: a few standard packages have forward declarations for // pieces supplied behind-the-scenes by package runtime. - extFiles := len(p.CgoFiles) + len(p.CFiles) + len(p.CXXFiles) + len(p.SFiles) + len(p.SysoFiles) + len(p.SwigFiles) + len(p.SwigCXXFiles) + extFiles := len(p.CgoFiles) + len(p.CFiles) + len(p.CXXFiles) + len(p.MFiles) + len(p.SFiles) + len(p.SysoFiles) + len(p.SwigFiles) + len(p.SwigCXXFiles) if p.Standard { switch p.ImportPath { case "os", "runtime/pprof", "sync", "time": @@ -1533,7 +1598,10 @@ func (gcToolchain) gc(b *builder, p *Package, obj string, importArgs []string, g gcargs = append(gcargs, "-installsuffix", buildContext.InstallSuffix) } - args := stringList(tool(archChar+"g"), "-o", ofile, buildGcflags, gcargs, "-D", p.localPrefix, importArgs) + args := stringList(tool(archChar+"g"), "-o", ofile, "-trimpath", b.work, buildGcflags, gcargs, "-D", p.localPrefix, importArgs) + if ofile == archive { + args = append(args, "-pack") + } for _, f := range gofiles { args = append(args, mkAbs(p.Dir, f)) } @@ -1544,7 +1612,7 @@ func (gcToolchain) gc(b *builder, p *Package, obj string, importArgs []string, g func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error { sfile = mkAbs(p.Dir, sfile) - return b.run(p.Dir, p.ImportPath, nil, tool(archChar+"a"), "-I", obj, "-o", ofile, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, sfile) + return b.run(p.Dir, p.ImportPath, nil, tool(archChar+"a"), "-trimpath", b.work, "-I", obj, "-o", ofile, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, sfile) } func (gcToolchain) pkgpath(basedir string, p *Package) string { @@ -1557,83 +1625,148 @@ func (gcToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []s for _, f := range ofiles { absOfiles = append(absOfiles, mkAbs(objDir, f)) } - return b.run(p.Dir, p.ImportPath, nil, tool("pack"), "grcP", b.work, mkAbs(objDir, afile), absOfiles) + cmd := "c" + absAfile := mkAbs(objDir, afile) + appending := false + if _, err := os.Stat(absAfile); err == nil { + appending = true + cmd = "r" + } + + cmdline := stringList("pack", cmd, absAfile, absOfiles) + + if appending { + if buildN || buildX { + b.showcmd(p.Dir, "%s # internal", joinUnambiguously(cmdline)) + } + if buildN { + return nil + } + if err := packInternal(b, absAfile, absOfiles); err != nil { + b.showOutput(p.Dir, p.ImportPath, err.Error()+"\n") + return errPrintedOutput + } + return nil + } + + // Need actual pack. + cmdline[0] = tool("pack") + return b.run(p.Dir, p.ImportPath, nil, cmdline) +} + +func packInternal(b *builder, afile string, ofiles []string) error { + dst, err := os.OpenFile(afile, os.O_WRONLY|os.O_APPEND, 0) + if err != nil { + return err + } + defer dst.Close() // only for error returns or panics + w := bufio.NewWriter(dst) + + for _, ofile := range ofiles { + src, err := os.Open(ofile) + if err != nil { + return err + } + fi, err := src.Stat() + if err != nil { + src.Close() + return err + } + // Note: Not using %-16.16s format because we care + // about bytes, not runes. + name := fi.Name() + if len(name) > 16 { + name = name[:16] + } else { + name += strings.Repeat(" ", 16-len(name)) + } + size := fi.Size() + fmt.Fprintf(w, "%s%-12d%-6d%-6d%-8o%-10d`\n", + name, 0, 0, 0, 0644, size) + n, err := io.Copy(w, src) + src.Close() + if err == nil && n < size { + err = io.ErrUnexpectedEOF + } else if err == nil && n > size { + err = fmt.Errorf("file larger than size reported by stat") + } + if err != nil { + return fmt.Errorf("copying %s to %s: %v", ofile, afile, err) + } + if size&1 != 0 { + w.WriteByte(0) + } + } + + if err := w.Flush(); err != nil { + return err + } + return dst.Close() } func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error { importArgs := b.includeArgs("-L", allactions) - swigDirs := make(map[string]bool) - swigArg := []string{} cxx := false for _, a := range allactions { - if a.p != nil && a.p.usesSwig() { - sd := a.p.swigDir(&buildContext) - if len(swigArg) == 0 { - swigArg = []string{"-r", sd} - } else if !swigDirs[sd] { - swigArg[1] += ":" - swigArg[1] += sd - } - swigDirs[sd] = true - if a.objdir != "" && !swigDirs[a.objdir] { - swigArg[1] += ":" - swigArg[1] += a.objdir - swigDirs[a.objdir] = true - } - } if a.p != nil && len(a.p.CXXFiles) > 0 { cxx = true } } ldflags := buildLdflags + // Limit slice capacity so that concurrent appends do not race on the shared array. + ldflags = ldflags[:len(ldflags):len(ldflags)] if buildContext.InstallSuffix != "" { ldflags = append(ldflags, "-installsuffix", buildContext.InstallSuffix) } - if cxx { - // The program includes C++ code. If the user has not - // specified the -extld option, then default to - // linking with the compiler named by the CXX - // environment variable, or g++ if CXX is not set. - extld := false - for _, f := range ldflags { - if f == "-extld" || strings.HasPrefix(f, "-extld=") { - extld = true - break - } + if p.omitDWARF { + ldflags = append(ldflags, "-w") + } + + // If the user has not specified the -extld option, then specify the + // appropriate linker. In case of C++ code, use the compiler named + // by the CXX environment variable or defaultCXX if CXX is not set. + // Else, use the CC environment variable and defaultCC as fallback. + extld := false + for _, f := range ldflags { + if f == "-extld" || strings.HasPrefix(f, "-extld=") { + extld = true + break } - if !extld { - compiler := strings.Fields(os.Getenv("CXX")) - if len(compiler) == 0 { - compiler = []string{"g++"} - } - ldflags = append(ldflags, "-extld="+compiler[0]) - if len(compiler) > 1 { - extldflags := false - add := strings.Join(compiler[1:], " ") - for i, f := range ldflags { - if f == "-extldflags" && i+1 < len(ldflags) { - ldflags[i+1] = add + " " + ldflags[i+1] - extldflags = true - break - } else if strings.HasPrefix(f, "-extldflags=") { - ldflags[i] = "-extldflags=" + add + " " + ldflags[i][len("-extldflags="):] - extldflags = true - break - } - } - if !extldflags { - ldflags = append(ldflags, "-extldflags="+add) + } + if !extld { + var compiler []string + if cxx { + compiler = envList("CXX", defaultCXX) + } else { + compiler = envList("CC", defaultCC) + } + ldflags = append(ldflags, "-extld="+compiler[0]) + if len(compiler) > 1 { + extldflags := false + add := strings.Join(compiler[1:], " ") + for i, f := range ldflags { + if f == "-extldflags" && i+1 < len(ldflags) { + ldflags[i+1] = add + " " + ldflags[i+1] + extldflags = true + break + } else if strings.HasPrefix(f, "-extldflags=") { + ldflags[i] = "-extldflags=" + add + " " + ldflags[i][len("-extldflags="):] + extldflags = true + break } } + if !extldflags { + ldflags = append(ldflags, "-extldflags="+add) + } } } - return b.run(".", p.ImportPath, nil, tool(archChar+"l"), "-o", out, importArgs, swigArg, ldflags, mainpkg) + return b.run(".", p.ImportPath, nil, tool(archChar+"l"), "-o", out, importArgs, ldflags, mainpkg) } func (gcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error { inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch)) cfile = mkAbs(p.Dir, cfile) - args := stringList(tool(archChar+"c"), "-F", "-V", "-w", "-I", objdir, "-I", inc, "-o", ofile, buildCcflags, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, cfile) + args := stringList(tool(archChar+"c"), "-F", "-V", "-w", "-trimpath", b.work, "-I", objdir, "-I", inc, "-o", ofile, buildCcflags, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, cfile) return b.run(p.Dir, p.ImportPath, nil, args) } @@ -1650,7 +1783,7 @@ func (gccgoToolchain) linker() string { return gccgoBin } -func (gccgoToolchain) gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, output []byte, err error) { +func (gccgoToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, output []byte, err error) { out := p.Name + ".o" ofile = obj + out gcargs := []string{"-g"} @@ -1698,52 +1831,62 @@ func (gccgoToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error { // gccgo needs explicit linking with all package dependencies, // and all LDFLAGS from cgo dependencies. - afiles := make(map[*Package]string) - sfiles := make(map[*Package][]string) + apackagesSeen := make(map[*Package]bool) + afiles := []string{} ldflags := b.gccArchArgs() cgoldflags := []string{} usesCgo := false cxx := false - for _, a := range allactions { - if a.p != nil { - if !a.p.Standard { - if afiles[a.p] == "" || a.objpkg != a.target { - afiles[a.p] = a.target + objc := false + + // Prefer the output of an install action to the output of a build action, + // because the install action will delete the output of the build action. + // Iterate over the list backward (reverse dependency order) so that we + // always see the install before the build. + for i := len(allactions) - 1; i >= 0; i-- { + a := allactions[i] + if !a.p.Standard { + if a.p != nil && !apackagesSeen[a.p] { + apackagesSeen[a.p] = true + if a.p.fake { + // move _test files to the top of the link order + afiles = append([]string{a.target}, afiles...) + } else { + afiles = append(afiles, a.target) } } + } + } + + for _, a := range allactions { + if a.p != nil { cgoldflags = append(cgoldflags, a.p.CgoLDFLAGS...) if len(a.p.CgoFiles) > 0 { usesCgo = true } if a.p.usesSwig() { - sd := a.p.swigDir(&buildContext) - if a.objdir != "" { - sd = a.objdir - } - for _, f := range stringList(a.p.SwigFiles, a.p.SwigCXXFiles) { - soname := a.p.swigSoname(f) - sfiles[a.p] = append(sfiles[a.p], filepath.Join(sd, soname)) - } usesCgo = true } if len(a.p.CXXFiles) > 0 { cxx = true } + if len(a.p.MFiles) > 0 { + objc = true + } } } - for _, afile := range afiles { - ldflags = append(ldflags, afile) - } - for _, sfiles := range sfiles { - ldflags = append(ldflags, sfiles...) - } + ldflags = append(ldflags, afiles...) ldflags = append(ldflags, cgoldflags...) + ldflags = append(ldflags, p.CgoLDFLAGS...) if usesCgo && goos == "linux" { ldflags = append(ldflags, "-Wl,-E") } if cxx { ldflags = append(ldflags, "-lstdc++") } + if objc { + ldflags = append(ldflags, "-lobjc") + } return b.run(".", p.ImportPath, nil, "gccgo", "-o", out, ofiles, "-Wl,-(", ldflags, "-Wl,-)", buildGccgoflags) } @@ -1856,16 +1999,13 @@ func (b *builder) gxxCmd(objdir string) []string { } // ccompilerCmd returns a command line prefix for the given environment -// variable and using the default command when the variable is empty +// variable and using the default command when the variable is empty. func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string { // NOTE: env.go's mkEnv knows that the first three // strings returned are "gcc", "-I", objdir (and cuts them off). - compiler := strings.Fields(os.Getenv(envvar)) - if len(compiler) == 0 { - compiler = strings.Fields(defcmd) - } - a := []string{compiler[0], "-I", objdir, "-g", "-O2"} + compiler := envList(envvar, defcmd) + a := []string{compiler[0], "-I", objdir} a = append(a, compiler[1:]...) // Definitely want -fPIC but on Windows gcc complains @@ -1892,6 +2032,9 @@ func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string { a = append(a, "-Qunused-arguments") } + // disable word wrapping in error messages + a = append(a, "-fmessage-length=0") + // On OS X, some of the compilers behave as if -fno-common // is always set, and the Mach-O linker in 6l/8l assumes this. // See http://golang.org/issue/3253. @@ -1915,8 +2058,28 @@ func (b *builder) gccArchArgs() []string { return nil } -func envList(key string) []string { - return strings.Fields(os.Getenv(key)) +// envList returns the value of the given environment variable broken +// into fields, using the default value when the variable is empty. +func envList(key, def string) []string { + v := os.Getenv(key) + if v == "" { + v = def + } + return strings.Fields(v) +} + +// Return the flags to use when invoking the C or C++ compilers, or cgo. +func (b *builder) cflags(p *Package, def bool) (cppflags, cflags, cxxflags, ldflags []string) { + var defaults string + if def { + defaults = "-g -O2" + } + + cppflags = stringList(envList("CGO_CPPFLAGS", ""), p.CgoCPPFLAGS) + cflags = stringList(envList("CGO_CFLAGS", defaults), p.CgoCFLAGS) + cxxflags = stringList(envList("CGO_CXXFLAGS", defaults), p.CgoCXXFLAGS) + ldflags = stringList(envList("CGO_LDFLAGS", defaults), p.CgoLDFLAGS) + return } var cgoRe = regexp.MustCompile(`[/\\:]`) @@ -1927,15 +2090,14 @@ var ( cgoLibGccFileOnce sync.Once ) -func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string, gxxfiles []string) (outGo, outObj []string, err error) { - if goos != toolGOOS { - return nil, nil, errors.New("cannot use cgo when compiling for a different operating system") - } +func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) { + cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoLDFLAGS := b.cflags(p, true) + _, cgoexeCFLAGS, _, _ := b.cflags(p, false) - cgoCPPFLAGS := stringList(envList("CGO_CPPFLAGS"), p.CgoCPPFLAGS) - cgoCFLAGS := stringList(envList("CGO_CFLAGS"), p.CgoCFLAGS) - cgoCXXFLAGS := stringList(envList("CGO_CXXFLAGS"), p.CgoCXXFLAGS) - cgoLDFLAGS := stringList(envList("CGO_LDFLAGS"), p.CgoLDFLAGS) + // If we are compiling Objective-C code, then we need to link against libobjc + if len(mfiles) > 0 { + cgoLDFLAGS = append(cgoLDFLAGS, "-lobjc") + } if pkgs := p.CgoPkgConfig; len(pkgs) > 0 { out, err := b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--cflags", pkgs) @@ -2001,7 +2163,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string, gxxfile } objExt = "o" } - if err := b.run(p.Dir, p.ImportPath, cgoenv, cgoExe, "-objdir", obj, cgoflags, "--", cgoCPPFLAGS, cgoCFLAGS, p.CgoFiles); err != nil { + if err := b.run(p.Dir, p.ImportPath, cgoenv, cgoExe, "-objdir", obj, cgoflags, "--", cgoCPPFLAGS, cgoexeCFLAGS, p.CgoFiles); err != nil { return nil, nil, err } outGo = append(outGo, gofiles...) @@ -2088,6 +2250,16 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string, gxxfile outObj = append(outObj, ofile) } + for _, file := range mfiles { + // Append .o to the file, just in case the pkg has file.c and file.m + ofile := obj + cgoRe.ReplaceAllString(file, "_") + ".o" + if err := b.gcc(p, ofile, cflags, file); err != nil { + return nil, nil, err + } + linkobj = append(linkobj, ofile) + outObj = append(outObj, ofile) + } + linkobj = append(linkobj, p.SysoFiles...) dynobj := obj + "_cgo_.o" if goarch == "arm" && goos == "linux" { // we need to use -pie for Linux/ARM to get accurate imported sym @@ -2145,24 +2317,39 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string, gxxfile // Run SWIG on all SWIG input files. // TODO: Don't build a shared library, once SWIG emits the necessary // pragmas for external linking. -func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles []string) (outGo, outObj []string, err error) { +func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) { + cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _ := b.cflags(p, true) + cflags := stringList(cgoCPPFLAGS, cgoCFLAGS) + cxxflags := stringList(cgoCPPFLAGS, cgoCXXFLAGS) - var extraObj []string for _, file := range gccfiles { ofile := obj + cgoRe.ReplaceAllString(file[:len(file)-1], "_") + "o" - if err := b.gcc(p, ofile, nil, file); err != nil { + if err := b.gcc(p, ofile, cflags, file); err != nil { return nil, nil, err } - extraObj = append(extraObj, ofile) + outObj = append(outObj, ofile) } for _, file := range gxxfiles { // Append .o to the file, just in case the pkg has file.c and file.cpp ofile := obj + cgoRe.ReplaceAllString(file, "_") + ".o" - if err := b.gxx(p, ofile, nil, file); err != nil { + if err := b.gxx(p, ofile, cxxflags, file); err != nil { return nil, nil, err } - extraObj = append(extraObj, ofile) + outObj = append(outObj, ofile) + } + + for _, file := range mfiles { + // Append .o to the file, just in case the pkg has file.c and file.cpp + ofile := obj + cgoRe.ReplaceAllString(file, "_") + ".o" + if err := b.gcc(p, ofile, cflags, file); err != nil { + return nil, nil, err + } + outObj = append(outObj, ofile) + } + + if err := b.swigVersionCheck(); err != nil { + return nil, nil, err } intgosize, err := b.swigIntSize(obj) @@ -2171,7 +2358,7 @@ func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles []string) (out } for _, f := range p.SwigFiles { - goFile, objFile, err := b.swigOne(p, f, obj, false, intgosize, extraObj) + goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, false, intgosize) if err != nil { return nil, nil, err } @@ -2181,9 +2368,12 @@ func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles []string) (out if objFile != "" { outObj = append(outObj, objFile) } + if gccObjFile != "" { + outObj = append(outObj, gccObjFile) + } } for _, f := range p.SwigCXXFiles { - goFile, objFile, err := b.swigOne(p, f, obj, true, intgosize, extraObj) + goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, true, intgosize) if err != nil { return nil, nil, err } @@ -2193,10 +2383,48 @@ func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles []string) (out if objFile != "" { outObj = append(outObj, objFile) } + if gccObjFile != "" { + outObj = append(outObj, gccObjFile) + } } return outGo, outObj, nil } +// Make sure SWIG is new enough. +var ( + swigCheckOnce sync.Once + swigCheck error +) + +func (b *builder) swigDoVersionCheck() error { + out, err := b.runOut("", "", nil, "swig", "-version") + if err != nil { + return err + } + re := regexp.MustCompile(`[vV]ersion +([\d])`) + matches := re.FindSubmatch(out) + if matches == nil { + // Can't find version number; hope for the best. + return nil + } + major, err := strconv.Atoi(string(matches[1])) + if err != nil { + // Can't find version number; hope for the best. + return nil + } + if major < 3 { + return errors.New("must have SWIG version >= 3.0") + } + return nil +} + +func (b *builder) swigVersionCheck() error { + swigCheckOnce.Do(func() { + swigCheck = b.swigDoVersionCheck() + }) + return swigCheck +} + // This code fails to build if sizeof(int) <= 32 const swigIntSizeCode = ` package main @@ -2217,14 +2445,22 @@ func (b *builder) swigIntSize(obj string) (intsize string, err error) { p := goFilesPackage(srcs) - if _, _, e := buildToolchain.gc(b, p, obj, nil, srcs); e != nil { + if _, _, e := buildToolchain.gc(b, p, "", obj, nil, srcs); e != nil { return "32", nil } return "64", nil } // Run SWIG on one SWIG input file. -func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize string, extraObj []string) (outGo, outObj string, err error) { +func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize string) (outGo, outObj, objGccObj string, err error) { + cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _ := b.cflags(p, true) + var cflags []string + if cxx { + cflags = stringList(cgoCPPFLAGS, cgoCXXFLAGS) + } else { + cflags = stringList(cgoCPPFLAGS, cgoCFLAGS) + } + n := 5 // length of ".swig" if cxx { n = 8 // length of ".swigcxx" @@ -2237,7 +2473,6 @@ func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize stri if cxx { gccExt = "cxx" } - soname := p.swigSoname(file) _, gccgo := buildToolchain.(gccgoToolchain) @@ -2246,12 +2481,14 @@ func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize stri "-go", "-intgosize", intgosize, "-module", base, - "-soname", soname, "-o", obj + gccBase + gccExt, "-outdir", obj, } if gccgo { args = append(args, "-gccgo") + if pkgpath := gccgoPkgpath(p); pkgpath != "" { + args = append(args, "-go-pkgpath", pkgpath) + } } if cxx { args = append(args, "-c++") @@ -2260,12 +2497,12 @@ func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize stri if out, err := b.runOut(p.Dir, p.ImportPath, nil, "swig", args, file); err != nil { if len(out) > 0 { if bytes.Contains(out, []byte("Unrecognized option -intgosize")) { - return "", "", errors.New("must have SWIG version >= 2.0.9\n") + return "", "", "", errors.New("must have SWIG version >= 3.0") } b.showOutput(p.Dir, p.ImportPath, b.processOutput(out)) - return "", "", errPrintedOutput + return "", "", "", errPrintedOutput } - return "", "", err + return "", "", "", err } var cObj string @@ -2273,32 +2510,23 @@ func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize stri // cc cObj = obj + cBase + archChar if err := buildToolchain.cc(b, p, obj, cObj, obj+cBase+"c"); err != nil { - return "", "", err + return "", "", "", err } } // gcc gccObj := obj + gccBase + "o" - if err := b.gcc(p, gccObj, []string{"-g", "-fPIC", "-O2"}, obj+gccBase+gccExt); err != nil { - return "", "", err - } - - // create shared library - osldflags := map[string][]string{ - "darwin": {"-dynamiclib", "-Wl,-undefined,dynamic_lookup"}, - "freebsd": {"-shared", "-lpthread", "-lm"}, - "linux": {"-shared", "-lpthread", "-lm"}, - "windows": {"-shared", "-lm", "-mthreads"}, - } - var cxxlib []string - if cxx { - cxxlib = []string{"-lstdc++"} + if !cxx { + if err := b.gcc(p, gccObj, cflags, obj+gccBase+gccExt); err != nil { + return "", "", "", err + } + } else { + if err := b.gxx(p, gccObj, cflags, obj+gccBase+gccExt); err != nil { + return "", "", "", err + } } - ldflags := stringList(osldflags[goos], cxxlib) - target := filepath.Join(obj, soname) - b.run(p.Dir, p.ImportPath, nil, b.gccCmd(p.Dir), "-o", target, gccObj, extraObj, ldflags) - return obj + goFile, cObj, nil + return obj + goFile, cObj, gccObj, nil } // An actionQueue is a priority queue of actions. diff --git a/src/cmd/go/clean.go b/src/cmd/go/clean.go index 16687f72f..16054a5b5 100644 --- a/src/cmd/go/clean.go +++ b/src/cmd/go/clean.go @@ -13,7 +13,7 @@ import ( ) var cmdClean = &Command{ - UsageLine: "clean [-i] [-r] [-n] [-x] [packages]", + UsageLine: "clean [-i] [-r] [-n] [-x] [build flags] [packages]", Short: "remove object files", Long: ` Clean removes object files from package source directories. @@ -52,23 +52,26 @@ dependencies of the packages named by the import paths. The -x flag causes clean to print remove commands as it executes them. +For more about build flags, see 'go help build'. + For more about specifying packages, see 'go help packages'. `, } var cleanI bool // clean -i flag -var cleanN bool // clean -n flag var cleanR bool // clean -r flag -var cleanX bool // clean -x flag func init() { // break init cycle cmdClean.Run = runClean cmdClean.Flag.BoolVar(&cleanI, "i", false, "") - cmdClean.Flag.BoolVar(&cleanN, "n", false, "") cmdClean.Flag.BoolVar(&cleanR, "r", false, "") - cmdClean.Flag.BoolVar(&cleanX, "x", false, "") + // -n and -x are important enough to be + // mentioned explicitly in the docs but they + // are part of the build flags. + + addBuildFlags(cmdClean) } func runClean(cmd *Command, args []string) { @@ -153,7 +156,7 @@ func clean(p *Package) { elem+".test.exe", ) - // Remove a potental executable for each .go file in the directory that + // Remove a potential executable for each .go file in the directory that // is not part of the directory's package. for _, dir := range dirs { name := dir.Name() @@ -169,7 +172,7 @@ func clean(p *Package) { } } - if cleanN || cleanX { + if buildN || buildX { b.showcmd(p.Dir, "rm -f %s", strings.Join(allRemove, " ")) } @@ -182,9 +185,9 @@ func clean(p *Package) { if dir.IsDir() { // TODO: Remove once Makefiles are forgotten. if cleanDir[name] { - if cleanN || cleanX { + if buildN || buildX { b.showcmd(p.Dir, "rm -r %s", name) - if cleanN { + if buildN { continue } } @@ -195,7 +198,7 @@ func clean(p *Package) { continue } - if cleanN { + if buildN { continue } @@ -205,28 +208,14 @@ func clean(p *Package) { } if cleanI && p.target != "" { - if cleanN || cleanX { + if buildN || buildX { b.showcmd("", "rm -f %s", p.target) } - if !cleanN { + if !buildN { removeFile(p.target) } } - if cleanI && p.usesSwig() { - for _, f := range stringList(p.SwigFiles, p.SwigCXXFiles) { - dir := p.swigDir(&buildContext) - soname := p.swigSoname(f) - target := filepath.Join(dir, soname) - if cleanN || cleanX { - b.showcmd("", "rm -f %s", target) - } - if !cleanN { - removeFile(target) - } - } - } - if cleanR { for _, p1 := range p.imports { clean(p1) diff --git a/src/cmd/go/context.go b/src/cmd/go/context.go new file mode 100644 index 000000000..68e518259 --- /dev/null +++ b/src/cmd/go/context.go @@ -0,0 +1,36 @@ +// Copyright 2014 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/build" +) + +type Context struct { + GOARCH string `json:",omitempty"` // target architecture + GOOS string `json:",omitempty"` // target operating system + GOROOT string `json:",omitempty"` // Go root + GOPATH string `json:",omitempty"` // Go path + CgoEnabled bool `json:",omitempty"` // whether cgo can be used + UseAllFiles bool `json:",omitempty"` // use files regardless of +build lines, file names + Compiler string `json:",omitempty"` // compiler to assume when computing target paths + BuildTags []string `json:",omitempty"` // build constraints to match in +build lines + ReleaseTags []string `json:",omitempty"` // releases the current release is compatible with + InstallSuffix string `json:",omitempty"` // suffix to use in the name of the install dir +} + +func newContext(c *build.Context) *Context { + return &Context{ + GOARCH: c.GOARCH, + GOOS: c.GOOS, + GOROOT: c.GOROOT, + CgoEnabled: c.CgoEnabled, + UseAllFiles: c.UseAllFiles, + Compiler: c.Compiler, + BuildTags: c.BuildTags, + ReleaseTags: c.ReleaseTags, + InstallSuffix: c.InstallSuffix, + } +} diff --git a/src/cmd/go/discovery.go b/src/cmd/go/discovery.go index 75228b52a..b9f427995 100644 --- a/src/cmd/go/discovery.go +++ b/src/cmd/go/discovery.go @@ -43,6 +43,9 @@ func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) { for { t, err = d.Token() if err != nil { + if err == io.EOF { + err = nil + } return } if e, ok := t.(xml.StartElement); ok && strings.EqualFold(e.Name.Local, "body") { diff --git a/src/cmd/go/doc.go b/src/cmd/go/doc.go index ebb2f37fd..9840804ce 100644 --- a/src/cmd/go/doc.go +++ b/src/cmd/go/doc.go @@ -33,6 +33,7 @@ Use "go help [command]" for more information about a command. Additional help topics: c calling between Go and C + filetype file types gopath GOPATH environment variable importpath import path syntax packages description of package lists @@ -46,7 +47,7 @@ Compile packages and dependencies Usage: - go build [-o output] [build flags] [packages] + go build [-o output] [-i] [build flags] [packages] Build compiles the packages named by the import paths, along with their dependencies, but it does not install the results. @@ -67,7 +68,10 @@ derives from the first file name mentioned, such as f1 for 'go build f1.go f2.go'; with no files provided ('go build'), the output file name is the base name of the containing directory. -The build flags are shared by the build, install, run, and test commands: +The -i flag installs the packages that are dependencies of the target. + +The build flags are shared by the build, clean, get, install, list, run, +and test commands: -a force rebuilding of packages that are already up-to-date. @@ -104,8 +108,8 @@ The build flags are shared by the build, install, run, and test commands: arguments to pass on each 5l, 6l, or 8l linker invocation. -tags 'tag list' a list of build tags to consider satisfied during the build. - See the documentation for the go/build package for - more information about build tags. + For more information about build tags, see the description of + build constraints in the documentation for the go/build package. The list flags accept a space-separated list of strings. To embed spaces in an element in the list, surround it with either single or double quotes. @@ -122,7 +126,7 @@ Remove object files Usage: - go clean [-i] [-r] [-n] [-x] [packages] + go clean [-i] [-r] [-n] [-x] [build flags] [packages] Clean removes object files from package source directories. The go command builds most objects in a temporary directory, @@ -160,6 +164,8 @@ dependencies of the packages named by the import paths. The -x flag causes clean to print remove commands as it executes them. +For more about build flags, see 'go help build'. + For more about specifying packages, see 'go help packages'. @@ -235,8 +241,7 @@ The -u flag instructs get to use the network to update the named packages and their dependencies. By default, get uses the network to check out missing packages but does not use it to look for updates to existing packages. -Get also accepts all the flags in the 'go build' and 'go install' commands, -to control the installation. See 'go help build'. +Get also accepts build flags to control the installation. See 'go help build'. When checking out or updating a package, get looks for a branch or tag that matches the locally installed version of Go. The most important @@ -271,7 +276,7 @@ List packages Usage: - go list [-e] [-race] [-f format] [-json] [-tags 'tag list'] [packages] + go list [-e] [-f format] [-json] [build flags] [packages] List lists the packages named by the import paths, one per line. @@ -283,8 +288,7 @@ The default output shows the package import path: The -f flag specifies an alternate format for the list, using the syntax of package template. The default output is equivalent to -f -'{{.ImportPath}}'. One extra template function is available, "join", -which calls strings.Join. The struct being passed to the template is: +'{{.ImportPath}}'. The struct being passed to the template is: type Package struct { Dir string // directory containing package sources @@ -303,6 +307,7 @@ which calls strings.Join. The struct being passed to the template is: IgnoredGoFiles []string // .go sources ignored due to build constraints CFiles []string // .c source files CXXFiles []string // .cc, .cxx and .cpp source files + MFiles []string // .m source files HFiles []string // .h, .hh, .hpp and .hxx source files SFiles []string // .s source files SwigFiles []string // .swig files @@ -331,6 +336,26 @@ which calls strings.Join. The struct being passed to the template is: XTestImports []string // imports from XTestGoFiles } +The template function "join" calls strings.Join. + +The template function "context" returns the build context, defined as: + + type Context struct { + GOARCH string // target architecture + GOOS string // target operating system + GOROOT string // Go root + GOPATH string // Go path + CgoEnabled bool // whether cgo can be used + UseAllFiles bool // use files regardless of +build lines, file names + Compiler string // compiler to assume when computing target paths + BuildTags []string // build constraints to match in +build lines + ReleaseTags []string // releases the current release is compatible with + InstallSuffix string // suffix to use in the name of the install dir + } + +For more information about the meaning of these fields see the documentation +for the go/build package's Context type. + The -json flag causes the package data to be printed in JSON format instead of using the template format. @@ -344,11 +369,7 @@ printing. Erroneous packages will have a non-empty ImportPath and a non-nil Error field; other information may or may not be missing (zeroed). -The -tags flag specifies a list of build tags, like in the 'go build' -command. - -The -race flag causes the package data to include the dependencies -required by the race detector. +For more about build flags, see 'go help build'. For more about specifying packages, see 'go help packages'. @@ -357,11 +378,20 @@ Compile and run Go program Usage: - go run [build flags] gofiles... [arguments...] + go run [build flags] [-exec xprog] gofiles... [arguments...] Run compiles and runs the main package comprising the named Go source files. A Go source file is defined to be a file ending in a literal ".go" suffix. +By default, 'go run' runs the compiled binary directly: 'a.out arguments...'. +If the -exec flag is given, 'go run' invokes the binary using xprog: 'xprog a.out arguments...'. +If the -exec flag is not given, GOOS or GOARCH is different from the system +default, and a program named go_$GOOS_$GOARCH_exec can be found +on the current search path, 'go run' invokes the binary using that program, +for example 'go_nacl_386_exec a.out arguments...'. This allows execution of +cross-compiled programs when a simulator or other execution method is +available. + For more about build flags, see 'go help build'. See also: go build. @@ -408,6 +438,10 @@ In addition to the build flags, the flags handled by 'go test' itself are: Install packages that are dependencies of the test. Do not run the test. + -exec xprog + Run the test binary using xprog. The behavior is the same as + in 'go run'. See 'go help run' for details. + The test binary also accepts flags that control execution of the test; these flags are also accessible by 'go test'. See 'go help testflag' for details. @@ -478,12 +512,49 @@ http://swig.org/. When running go build, any file with a .swig extension will be passed to SWIG. Any file with a .swigcxx extension will be passed to SWIG with the -c++ option. -When either cgo or SWIG is used, go build will pass any .c, .s, or .S -files to the C compiler, and any .cc, .cpp, .cxx files to the C++ +When either cgo or SWIG is used, go build will pass any .c, .m, .s, +or .S files to the C compiler, and any .cc, .cpp, .cxx files to the C++ compiler. The CC or CXX environment variables may be set to determine the C or C++ compiler, respectively, to use. +File types + +The go command examines the contents of a restricted set of files +in each directory. It identifies which files to examine based on +the extension of the file name. These extensions are: + + .go + Go source files. + .c, .h + C source files. + If the package uses cgo, these will be compiled with the + OS-native compiler (typically gcc); otherwise they will be + compiled with the Go-specific support compiler, + 5c, 6c, or 8c, etc. as appropriate. + .cc, .cpp, .cxx, .hh, .hpp, .hxx + C++ source files. Only useful with cgo or SWIG, and always + compiled with the OS-native compiler. + .m + Objective-C source files. Only useful with cgo, and always + compiled with the OS-native compiler. + .s, .S + Assembler source files. + If the package uses cgo, these will be assembled with the + OS-native assembler (typically gcc (sic)); otherwise they + will be assembled with the Go-specific support assembler, + 5a, 6a, or 8a, etc., as appropriate. + .swig, .swigcxx + SWIG definition files. + .syso + System object files. + +Files of each of these types except .syso may contain build +constraints, but the go command stops scanning for build constraints +at the first item in the file that is not a blank line or //-style +line comment. + + GOPATH environment variable The Go path is used to resolve import statements. @@ -638,7 +709,7 @@ example.org/user/foo or foo.hg, and import "example.org/repo.git/foo/bar" denotes the foo/bar directory of the Git repository at -example.com/repo or repo.git. +example.org/repo or repo.git. When a version control system supports multiple protocols, each is tried in turn when downloading. For example, a Git @@ -788,7 +859,8 @@ control the execution of any test: -covermode set,count,atomic Set the mode for coverage analysis for the package[s] - being tested. The default is "set". + being tested. The default is "set" unless -race is enabled, + in which case it is "atomic". The values: set: bool: does this statement run? count: int: how many times does this statement run? @@ -823,9 +895,7 @@ control the execution of any test: Enable more precise (and expensive) memory profiles by setting runtime.MemProfileRate. See 'godoc runtime MemProfileRate'. To profile all memory allocations, use -test.memprofilerate=1 - and set the environment variable GOGC=off to disable the - garbage collector, provided the test can run in the available - memory without garbage collection. + and pass --alloc_space flag to the pprof tool. -outputdir directory Place output files from profiling in the specified directory, diff --git a/src/cmd/go/env.go b/src/cmd/go/env.go index 2db821797..26d37df4f 100644 --- a/src/cmd/go/env.go +++ b/src/cmd/go/env.go @@ -85,18 +85,28 @@ func runEnv(cmd *Command, args []string) { return } - switch runtime.GOOS { - default: - for _, e := range env { - fmt.Printf("%s=\"%s\"\n", e.name, e.value) - } - case "plan9": - for _, e := range env { - fmt.Printf("%s='%s'\n", e.name, strings.Replace(e.value, "'", "''", -1)) - } - case "windows": - for _, e := range env { - fmt.Printf("set %s=%s\n", e.name, e.value) + for _, e := range env { + if e.name != "TERM" { + switch runtime.GOOS { + default: + fmt.Printf("%s=\"%s\"\n", e.name, e.value) + case "plan9": + if strings.IndexByte(e.value, '\x00') < 0 { + fmt.Printf("%s='%s'\n", e.name, strings.Replace(e.value, "'", "''", -1)) + } else { + v := strings.Split(e.value, "\x00") + fmt.Printf("%s=(", e.name) + for x, s := range v { + if x > 0 { + fmt.Printf(" ") + } + fmt.Printf("%s", s) + } + fmt.Printf(")\n") + } + case "windows": + fmt.Printf("set %s=%s\n", e.name, e.value) + } } } } diff --git a/src/cmd/go/get.go b/src/cmd/go/get.go index e61da7e2a..e708fcf77 100644 --- a/src/cmd/go/get.go +++ b/src/cmd/go/get.go @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// TODO: Dashboard upload - package main import ( @@ -37,8 +35,7 @@ The -u flag instructs get to use the network to update the named packages and their dependencies. By default, get uses the network to check out missing packages but does not use it to look for updates to existing packages. -Get also accepts all the flags in the 'go build' and 'go install' commands, -to control the installation. See 'go help build'. +Get also accepts build flags to control the installation. See 'go help build'. When checking out or updating a package, get looks for a branch or tag that matches the locally installed version of Go. The most important @@ -73,7 +70,7 @@ func runGet(cmd *Command, args []string) { } exitIfErrors() - // Phase 2. Rescan packages and reevaluate args list. + // Phase 2. Rescan packages and re-evaluate args list. // Code we downloaded and all code that depends on it // needs to be evicted from the package cache so that @@ -143,6 +140,10 @@ var downloadRootCache = map[string]bool{} // for the package named by the argument. func download(arg string, stk *importStack, getTestDeps bool) { p := loadPackage(arg, stk) + if p.Error != nil && p.Error.hard { + errorf("%s", p.Error) + return + } // There's nothing to do if this is a package in the standard library. if p.Standard { diff --git a/src/cmd/go/help.go b/src/cmd/go/help.go index 71e55175a..40da7e1f5 100644 --- a/src/cmd/go/help.go +++ b/src/cmd/go/help.go @@ -19,8 +19,8 @@ http://swig.org/. When running go build, any file with a .swig extension will be passed to SWIG. Any file with a .swigcxx extension will be passed to SWIG with the -c++ option. -When either cgo or SWIG is used, go build will pass any .c, .s, or .S -files to the C compiler, and any .cc, .cpp, .cxx files to the C++ +When either cgo or SWIG is used, go build will pass any .c, .m, .s, +or .S files to the C compiler, and any .cc, .cpp, .cxx files to the C++ compiler. The CC or CXX environment variables may be set to determine the C or C++ compiler, respectively, to use. `, @@ -182,7 +182,7 @@ example.org/user/foo or foo.hg, and import "example.org/repo.git/foo/bar" denotes the foo/bar directory of the Git repository at -example.com/repo or repo.git. +example.org/repo or repo.git. When a version control system supports multiple protocols, each is tried in turn when downloading. For example, a Git @@ -295,3 +295,43 @@ but new packages are always downloaded into the first directory in the list. `, } + +var helpFileType = &Command{ + UsageLine: "filetype", + Short: "file types", + Long: ` +The go command examines the contents of a restricted set of files +in each directory. It identifies which files to examine based on +the extension of the file name. These extensions are: + + .go + Go source files. + .c, .h + C source files. + If the package uses cgo, these will be compiled with the + OS-native compiler (typically gcc); otherwise they will be + compiled with the Go-specific support compiler, + 5c, 6c, or 8c, etc. as appropriate. + .cc, .cpp, .cxx, .hh, .hpp, .hxx + C++ source files. Only useful with cgo or SWIG, and always + compiled with the OS-native compiler. + .m + Objective-C source files. Only useful with cgo, and always + compiled with the OS-native compiler. + .s, .S + Assembler source files. + If the package uses cgo, these will be assembled with the + OS-native assembler (typically gcc (sic)); otherwise they + will be assembled with the Go-specific support assembler, + 5a, 6a, or 8a, etc., as appropriate. + .swig, .swigcxx + SWIG definition files. + .syso + System object files. + +Files of each of these types except .syso may contain build +constraints, but the go command stops scanning for build constraints +at the first item in the file that is not a blank line or //-style +line comment. + `, +} diff --git a/src/cmd/go/list.go b/src/cmd/go/list.go index f56ebed38..0ead43502 100644 --- a/src/cmd/go/list.go +++ b/src/cmd/go/list.go @@ -14,7 +14,7 @@ import ( ) var cmdList = &Command{ - UsageLine: "list [-e] [-race] [-f format] [-json] [-tags 'tag list'] [packages]", + UsageLine: "list [-e] [-f format] [-json] [build flags] [packages]", Short: "list packages", Long: ` List lists the packages named by the import paths, one per line. @@ -27,8 +27,7 @@ The default output shows the package import path: The -f flag specifies an alternate format for the list, using the syntax of package template. The default output is equivalent to -f -'{{.ImportPath}}'. One extra template function is available, "join", -which calls strings.Join. The struct being passed to the template is: +'{{.ImportPath}}'. The struct being passed to the template is: type Package struct { Dir string // directory containing package sources @@ -47,6 +46,7 @@ which calls strings.Join. The struct being passed to the template is: IgnoredGoFiles []string // .go sources ignored due to build constraints CFiles []string // .c source files CXXFiles []string // .cc, .cxx and .cpp source files + MFiles []string // .m source files HFiles []string // .h, .hh, .hpp and .hxx source files SFiles []string // .s source files SwigFiles []string // .swig files @@ -75,6 +75,26 @@ which calls strings.Join. The struct being passed to the template is: XTestImports []string // imports from XTestGoFiles } +The template function "join" calls strings.Join. + +The template function "context" returns the build context, defined as: + + type Context struct { + GOARCH string // target architecture + GOOS string // target operating system + GOROOT string // Go root + GOPATH string // Go path + CgoEnabled bool // whether cgo can be used + UseAllFiles bool // use files regardless of +build lines, file names + Compiler string // compiler to assume when computing target paths + BuildTags []string // build constraints to match in +build lines + ReleaseTags []string // releases the current release is compatible with + InstallSuffix string // suffix to use in the name of the install dir + } + +For more information about the meaning of these fields see the documentation +for the go/build package's Context type. + The -json flag causes the package data to be printed in JSON format instead of using the template format. @@ -88,11 +108,7 @@ printing. Erroneous packages will have a non-empty ImportPath and a non-nil Error field; other information may or may not be missing (zeroed). -The -tags flag specifies a list of build tags, like in the 'go build' -command. - -The -race flag causes the package data to include the dependencies -required by the race detector. +For more about build flags, see 'go help build'. For more about specifying packages, see 'go help packages'. `, @@ -100,24 +116,18 @@ For more about specifying packages, see 'go help packages'. func init() { cmdList.Run = runList // break init cycle - cmdList.Flag.Var(buildCompiler{}, "compiler", "") - cmdList.Flag.Var((*stringsFlag)(&buildContext.BuildTags), "tags", "") + addBuildFlags(cmdList) } var listE = cmdList.Flag.Bool("e", false, "") var listFmt = cmdList.Flag.String("f", "{{.ImportPath}}", "") var listJson = cmdList.Flag.Bool("json", false, "") -var listRace = cmdList.Flag.Bool("race", false, "") var nl = []byte{'\n'} func runList(cmd *Command, args []string) { out := newTrackingWriter(os.Stdout) defer out.w.Flush() - if *listRace { - buildRace = true - } - var do func(*Package) if *listJson { do = func(p *Package) { @@ -130,7 +140,18 @@ func runList(cmd *Command, args []string) { out.Write(nl) } } else { - tmpl, err := template.New("main").Funcs(template.FuncMap{"join": strings.Join}).Parse(*listFmt) + var cachedCtxt *Context + context := func() *Context { + if cachedCtxt == nil { + cachedCtxt = newContext(&buildContext) + } + return cachedCtxt + } + fm := template.FuncMap{ + "join": strings.Join, + "context": context, + } + tmpl, err := template.New("main").Funcs(fm).Parse(*listFmt) if err != nil { fatalf("%s", err) } @@ -140,7 +161,7 @@ func runList(cmd *Command, args []string) { fatalf("%s", err) } if out.NeedNL() { - out.Write([]byte{'\n'}) + out.Write(nl) } } } diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go index df0cf1b3f..5b1194aaa 100644 --- a/src/cmd/go/main.go +++ b/src/cmd/go/main.go @@ -89,6 +89,7 @@ var commands = []*Command{ cmdVet, helpC, + helpFileType, helpGopath, helpImportPath, helpPackages, @@ -238,6 +239,11 @@ func printUsage(w io.Writer) { } func usage() { + // special case "go test -h" + if len(os.Args) > 1 && os.Args[1] == "test" { + help([]string{"testflag"}) + os.Exit(2) + } printUsage(os.Stderr) os.Exit(2) } diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go index 71f14c74a..d45df265b 100644 --- a/src/cmd/go/pkg.go +++ b/src/cmd/go/pkg.go @@ -42,6 +42,7 @@ type Package struct { IgnoredGoFiles []string `json:",omitempty"` // .go sources ignored due to build constraints CFiles []string `json:",omitempty"` // .c source files CXXFiles []string `json:",omitempty"` // .cc, .cpp and .cxx source files + MFiles []string `json:",omitempty"` // .m source files HFiles []string `json:",omitempty"` // .h, .hh, .hpp and .hxx source files SFiles []string `json:",omitempty"` // .s source files SwigFiles []string `json:",omitempty"` // .swig files @@ -88,6 +89,7 @@ type Package struct { exeName string // desired name for temporary executable coverMode string // preprocess Go source files with the coverage tool in this mode coverVars map[string]*CoverVar // variables created by coverage analysis + omitDWARF bool // tell linker not to write DWARF information } // CoverVar holds the name of the generated coverage variables targeting the named file. @@ -113,6 +115,7 @@ func (p *Package) copyBuild(pp *build.Package) { p.IgnoredGoFiles = pp.IgnoredGoFiles p.CFiles = pp.CFiles p.CXXFiles = pp.CXXFiles + p.MFiles = pp.MFiles p.HFiles = pp.HFiles p.SFiles = pp.SFiles p.SwigFiles = pp.SwigFiles @@ -136,12 +139,13 @@ type PackageError struct { Pos string // position of error Err string // the error itself isImportCycle bool // the error is an import cycle + hard bool // whether the error is soft or hard; soft errors are ignored in some places } func (p *PackageError) Error() string { // Import cycles deserve special treatment. if p.isImportCycle { - return fmt.Sprintf("%s: %s\npackage %s\n", p.Pos, p.Err, strings.Join(p.ImportStack, "\n\timports ")) + return fmt.Sprintf("%s\npackage %s\n", p.Err, strings.Join(p.ImportStack, "\n\timports ")) } if p.Pos != "" { // Omit import stack. The full path to the file where the error @@ -304,9 +308,14 @@ const ( // goTools is a map of Go program import path to install target directory. var goTools = map[string]targetDir{ + "cmd/addr2line": toTool, "cmd/api": toTool, "cmd/cgo": toTool, "cmd/fix": toTool, + "cmd/link": toTool, + "cmd/nm": toTool, + "cmd/objdump": toTool, + "cmd/pack": toTool, "cmd/yacc": toTool, "code.google.com/p/go.tools/cmd/cover": toTool, "code.google.com/p/go.tools/cmd/godoc": toBin, @@ -454,6 +463,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package p.IgnoredGoFiles, p.CFiles, p.CXXFiles, + p.MFiles, p.HFiles, p.SFiles, p.SysoFiles, @@ -551,24 +561,6 @@ func (p *Package) usesCgo() bool { return len(p.CgoFiles) > 0 } -// swigSoname returns the name of the shared library we create for a -// SWIG input file. -func (p *Package) swigSoname(file string) string { - return strings.Replace(p.ImportPath, "/", "-", -1) + "-" + strings.Replace(file, ".", "-", -1) + ".so" -} - -// swigDir returns the name of the shared SWIG directory for a -// package. -func (p *Package) swigDir(ctxt *build.Context) string { - dir := p.build.PkgRoot - if ctxt.Compiler == "gccgo" { - dir = filepath.Join(dir, "gccgo_"+ctxt.GOOS+"_"+ctxt.GOARCH) - } else { - dir = filepath.Join(dir, ctxt.GOOS+"_"+ctxt.GOARCH) - } - return filepath.Join(dir, "swig") -} - // packageList returns the list of packages in the dag rooted at roots // as visited in a depth-first post-order traversal. func packageList(roots []*Package) []*Package { @@ -681,7 +673,7 @@ func isStale(p *Package, topRoot map[string]bool) bool { return false } - srcs := stringList(p.GoFiles, p.CFiles, p.CXXFiles, p.HFiles, p.SFiles, p.CgoFiles, p.SysoFiles, p.SwigFiles, p.SwigCXXFiles) + srcs := stringList(p.GoFiles, p.CFiles, p.CXXFiles, p.MFiles, p.HFiles, p.SFiles, p.CgoFiles, p.SysoFiles, p.SwigFiles, p.SwigCXXFiles) for _, src := range srcs { if olderThan(filepath.Join(p.Dir, src)) { return true @@ -724,6 +716,7 @@ func loadPackage(arg string, stk *importStack) *Package { Error: &PackageError{ ImportStack: stk.copy(), Err: fmt.Sprintf("invalid import path: cmd/... is reserved for Go commands"), + hard: true, }, } return p diff --git a/src/cmd/go/pkg_test.go b/src/cmd/go/pkg_test.go new file mode 100644 index 000000000..06b9f0ac6 --- /dev/null +++ b/src/cmd/go/pkg_test.go @@ -0,0 +1,73 @@ +// Copyright 2014 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 ( + "reflect" + "strings" + "testing" +) + +var foldDupTests = []struct { + list []string + f1, f2 string +}{ + {stringList("math/rand", "math/big"), "", ""}, + {stringList("math", "strings"), "", ""}, + {stringList("strings"), "", ""}, + {stringList("strings", "strings"), "strings", "strings"}, + {stringList("Rand", "rand", "math", "math/rand", "math/Rand"), "Rand", "rand"}, +} + +func TestFoldDup(t *testing.T) { + for _, tt := range foldDupTests { + f1, f2 := foldDup(tt.list) + if f1 != tt.f1 || f2 != tt.f2 { + t.Errorf("foldDup(%q) = %q, %q, want %q, %q", tt.list, f1, f2, tt.f1, tt.f2) + } + } +} + +var parseMetaGoImportsTests = []struct { + in string + out []metaImport +}{ + { + ``, + []metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}}, + }, + { + ` + `, + []metaImport{ + {"foo/bar", "git", "https://github.com/rsc/foo/bar"}, + {"baz/quux", "git", "http://github.com/rsc/baz/quux"}, + }, + }, + { + ` + + `, + []metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}}, + }, + { + ` + `, + []metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}}, + }, +} + +func TestParseMetaGoImports(t *testing.T) { + for i, tt := range parseMetaGoImportsTests { + out, err := parseMetaGoImports(strings.NewReader(tt.in)) + if err != nil { + t.Errorf("test#%d: %v", i, err) + continue + } + if !reflect.DeepEqual(out, tt.out) { + t.Errorf("test#%d:\n\thave %q\n\twant %q", i, out, tt.out) + } + } +} diff --git a/src/cmd/go/run.go b/src/cmd/go/run.go index e6dadd229..ef8aa95a3 100644 --- a/src/cmd/go/run.go +++ b/src/cmd/go/run.go @@ -8,16 +8,43 @@ import ( "fmt" "os" "os/exec" + "runtime" "strings" ) +var execCmd []string // -exec flag, for run and test + +func findExecCmd() []string { + if execCmd != nil { + return execCmd + } + execCmd = []string{} // avoid work the second time + if goos == runtime.GOOS && goarch == runtime.GOARCH { + return execCmd + } + path, err := exec.LookPath(fmt.Sprintf("go_%s_%s_exec", goos, goarch)) + if err == nil { + execCmd = []string{path} + } + return execCmd +} + var cmdRun = &Command{ - UsageLine: "run [build flags] gofiles... [arguments...]", + UsageLine: "run [build flags] [-exec xprog] gofiles... [arguments...]", Short: "compile and run Go program", Long: ` Run compiles and runs the main package comprising the named Go source files. A Go source file is defined to be a file ending in a literal ".go" suffix. +By default, 'go run' runs the compiled binary directly: 'a.out arguments...'. +If the -exec flag is given, 'go run' invokes the binary using xprog: 'xprog a.out arguments...'. +If the -exec flag is not given, GOOS or GOARCH is different from the system +default, and a program named go_$GOOS_$GOARCH_exec can be found +on the current search path, 'go run' invokes the binary using that program, +for example 'go_nacl_386_exec a.out arguments...'. This allows execution of +cross-compiled programs when a simulator or other execution method is +available. + For more about build flags, see 'go help build'. See also: go build. @@ -28,6 +55,7 @@ func init() { cmdRun.Run = runRun // break init loop addBuildFlags(cmdRun) + cmdRun.Flag.Var((*stringsFlag)(&execCmd), "exec", "") } func printStderr(args ...interface{}) (int, error) { @@ -58,6 +86,7 @@ func runRun(cmd *Command, args []string) { if p.Error != nil { fatalf("%s", p.Error) } + p.omitDWARF = true for _, err := range p.DepsErrors { errorf("%s", err) } @@ -89,20 +118,20 @@ func runRun(cmd *Command, args []string) { // runProgram is the action for running a binary that has already // been compiled. We ignore exit status. func (b *builder) runProgram(a *action) error { + cmdline := stringList(findExecCmd(), a.deps[0].target, a.args) if buildN || buildX { - b.showcmd("", "%s %s", a.deps[0].target, strings.Join(a.args, " ")) + b.showcmd("", "%s", strings.Join(cmdline, " ")) if buildN { return nil } } - runStdin(a.deps[0].target, a.args) + runStdin(cmdline) return nil } // runStdin is like run, but connects Stdin. -func runStdin(cmdargs ...interface{}) { - cmdline := stringList(cmdargs...) +func runStdin(cmdline []string) { cmd := exec.Command(cmdline[0], cmdline[1:]...) cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout diff --git a/src/cmd/go/signal_unix.go b/src/cmd/go/signal_unix.go index 00c71657f..e86cd4652 100644 --- a/src/cmd/go/signal_unix.go +++ b/src/cmd/go/signal_unix.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. -// +build darwin dragonfly freebsd linux netbsd openbsd +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris package main diff --git a/src/cmd/go/test.bash b/src/cmd/go/test.bash index f71d67818..0060ce218 100755 --- a/src/cmd/go/test.bash +++ b/src/cmd/go/test.bash @@ -36,8 +36,9 @@ stop() { ok=true allok=true -unset GOPATH unset GOBIN +unset GOPATH +unset GOROOT TEST 'file:line in error messages' # Test that error messages have file:line information at beginning of @@ -258,6 +259,7 @@ if [ ! -x $d/gobin/godoc ]; then fi TEST godoc installs into GOROOT +GOROOT=$(./testgo env GOROOT) rm -f $GOROOT/bin/godoc ./testgo install code.google.com/p/go.tools/cmd/godoc if [ ! -x $GOROOT/bin/godoc ]; then @@ -425,10 +427,10 @@ d=$(TMPDIR=$tmp mktemp -d -t testgoXXX) mkdir -p $d/src ( ln -s $d $d/src/dir1 - cd $d/src/dir1 - echo package p >p.go + cd $d/src + echo package p >dir1/p.go export GOPATH=$d - if [ "$($old/testgo list -f '{{.Root}}' .)" != "$d" ]; then + if [ "$($old/testgo list -f '{{.Root}}' dir1)" != "$d" ]; then echo Confused by symlinks. echo "Package in current directory $(pwd) should have Root $d" env|grep WD @@ -477,14 +479,20 @@ rm -rf $d TEST case collisions '(issue 4773)' d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX) export GOPATH=$d -mkdir -p $d/src/example/a $d/src/example/b +mkdir -p $d/src/example/{a/pkg,a/Pkg,b} cat >$d/src/example/a/a.go <$d/src/example/a/pkg/pkg.go <$d/src/example/a/Pkg/pkg.go <$d/out; then echo go list example/a should have failed, did not. ok=false @@ -545,7 +553,7 @@ fi # The error for go install should mention the conflicting directory. err=$(! ./testgo install ./testdata/shadow/root2/src/foo 2>&1) -if [ "$err" != "go install: no install location for directory $(pwd)/testdata/shadow/root2/src/foo hidden by $(pwd)/testdata/shadow/root1/src/foo" ]; then +if [ "$err" != "go install: no install location for $(pwd)/testdata/shadow/root2/src/foo: hidden by $(pwd)/testdata/shadow/root1/src/foo" ]; then echo wrong shadowed install error: "$err" ok=false fi @@ -555,10 +563,59 @@ TEST source file name order preserved ./testgo test testdata/example[12]_test.go || ok=false # Check that coverage analysis works at all. -# Don't worry about the exact numbers +# Don't worry about the exact numbers but require not 0.0%. +checkcoverage() { + if grep '[^0-9]0\.0%' testdata/cover.txt >/dev/null; then + echo 'some coverage results are 0.0%' + ok=false + fi + cat testdata/cover.txt + rm -f testdata/cover.txt +} + TEST coverage runs -./testgo test -short -coverpkg=strings strings regexp || ok=false -./testgo test -short -cover strings math regexp || ok=false +./testgo test -short -coverpkg=strings strings regexp >testdata/cover.txt 2>&1 || ok=false +./testgo test -short -cover strings math regexp >>testdata/cover.txt 2>&1 || ok=false +checkcoverage + +# Check that coverage analysis uses set mode. +TEST coverage uses set mode +if ./testgo test -short -cover encoding/binary -coverprofile=testdata/cover.out >testdata/cover.txt 2>&1; then + if ! grep -q 'mode: set' testdata/cover.out; then + ok=false + fi + checkcoverage +else + ok=false +fi +rm -f testdata/cover.out testdata/cover.txt + +TEST coverage uses atomic mode for -race. +if ./testgo test -short -race -cover encoding/binary -coverprofile=testdata/cover.out >testdata/cover.txt 2>&1; then + if ! grep -q 'mode: atomic' testdata/cover.out; then + ok=false + fi + checkcoverage +else + ok=false +fi +rm -f testdata/cover.out + +TEST coverage uses actual setting to override even for -race. +if ./testgo test -short -race -cover encoding/binary -covermode=count -coverprofile=testdata/cover.out >testdata/cover.txt 2>&1; then + if ! grep -q 'mode: count' testdata/cover.out; then + ok=false + fi + checkcoverage +else + ok=false +fi +rm -f testdata/cover.out + +TEST coverage with cgo +d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX) +./testgo test -short -cover ./testdata/cgocover >testdata/cover.txt 2>&1 || ok=false +checkcoverage TEST cgo depends on syscall rm -rf $GOROOT/pkg/*_race @@ -600,7 +657,7 @@ export GOPATH=$d mkdir -p $d/src/origin echo ' package origin -// #cgo LDFLAGS: -Wl,-rpath -Wl,$ORIGIN +// #cgo !darwin LDFLAGS: -Wl,-rpath -Wl,$ORIGIN // void f(void) {} import "C" @@ -620,6 +677,136 @@ if ! ./testgo test -c -test.bench=XXX fmt; then fi rm -f fmt.test +TEST 'Issue 7573: cmd/cgo: undefined reference when linking a C-library using gccgo' +d=$(mktemp -d -t testgoXXX) +export GOPATH=$d +mkdir -p $d/src/cgoref +ldflags="-L alibpath -lalib" +echo " +package main +// #cgo LDFLAGS: $ldflags +// void f(void) {} +import \"C\" + +func main() { C.f() } +" >$d/src/cgoref/cgoref.go +go_cmds="$(./testgo build -n -compiler gccgo cgoref 2>&1 1>/dev/null)" +ldflags_count="$(echo "$go_cmds" | egrep -c "^gccgo.*$(echo $ldflags | sed -e 's/-/\\-/g')" || true)" +if [ "$ldflags_count" -lt 1 ]; then + echo "No Go-inline "#cgo LDFLAGS:" (\"$ldflags\") passed to gccgo linking stage." + ok=false +fi +rm -rf $d +unset ldflags_count +unset go_cmds +unset ldflags +unset GOPATH + +TEST list template can use context function +if ! ./testgo list -f "GOARCH: {{context.GOARCH}}"; then + echo unable to use context in list template + ok=false +fi + +TEST 'Issue 7108: cmd/go: "go test" should fail if package does not build' +export GOPATH=$(pwd)/testdata +if ./testgo test notest >/dev/null 2>&1; then + echo 'go test notest succeeded, but should fail' + ok=false +fi +unset GOPATH + +TEST 'Issue 6844: cmd/go: go test -a foo does not rebuild regexp' +if ! ./testgo test -x -a -c testdata/dep_test.go 2>deplist; then + echo "go test -x -a -c testdata/dep_test.go failed" + ok=false +elif ! grep -q regexp deplist; then + echo "go test -x -a -c testdata/dep_test.go did not rebuild regexp" + ok=false +fi +rm -f deplist +rm -f deps.test + +TEST list template can use context function +if ! ./testgo list -f "GOARCH: {{context.GOARCH}}"; then + echo unable to use context in list template + ok=false +fi + +TEST build -i installs dependencies +d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX) +export GOPATH=$d +mkdir -p $d/src/x/y/foo $d/src/x/y/bar +echo ' +package foo +func F() {} +' >$d/src/x/y/foo/foo.go +echo ' +package bar +import "x/y/foo" +func F() { foo.F() } +' >$d/src/x/y/bar/bar.go +if ! ./testgo build -v -i x/y/bar &> $d/err; then + echo build -i failed + cat $d/err + ok=false +elif ! grep x/y/foo $d/err >/dev/null; then + echo first build -i did not build x/y/foo + cat $d/err + ok=false +fi +if ! ./testgo build -v -i x/y/bar &> $d/err; then + echo second build -i failed + cat $d/err + ok=false +elif grep x/y/foo $d/err >/dev/null; then + echo second build -i built x/y/foo + cat $d/err + ok=false +fi +rm -rf $d +unset GOPATH + +TEST 'go build in test-only directory fails with a good error' +if ./testgo build ./testdata/testonly 2>testdata/err.out; then + echo "go build ./testdata/testonly succeeded, should have failed" + ok=false +elif ! grep 'no buildable Go' testdata/err.out >/dev/null; then + echo "go build ./testdata/testonly produced unexpected error:" + cat testdata/err.out + ok=false +fi +rm -f testdata/err.out + +TEST 'go test detects test-only import cycles' +export GOPATH=$(pwd)/testdata +if ./testgo test -c testcycle/p3 2>testdata/err.out; then + echo "go test testcycle/p3 succeeded, should have failed" + ok=false +elif ! grep 'import cycle not allowed in test' testdata/err.out >/dev/null; then + echo "go test testcycle/p3 produced unexpected error:" + cat testdata/err.out + ok=false +fi +rm -f testdata/err.out +unset GOPATH + +TEST 'go test foo_test.go works' +if ! ./testgo test testdata/standalone_test.go; then + echo "go test testdata/standalone_test.go failed" + ok=false +fi + +TEST 'go test xtestonly works' +export GOPATH=$(pwd)/testdata +./testgo clean -i xtestonly +if ! ./testgo test xtestonly >/dev/null; then + echo "go test xtestonly failed" + ok=false +fi +unset GOPATH + + # clean up if $started; then stop; fi rm -rf testdata/bin testdata/bin1 diff --git a/src/cmd/go/test.go b/src/cmd/go/test.go index 06ac9d206..5935c98db 100644 --- a/src/cmd/go/test.go +++ b/src/cmd/go/test.go @@ -72,6 +72,10 @@ In addition to the build flags, the flags handled by 'go test' itself are: Install packages that are dependencies of the test. Do not run the test. + -exec xprog + Run the test binary using xprog. The behavior is the same as + in 'go run'. See 'go help run' for details. + The test binary also accepts flags that control execution of the test; these flags are also accessible by 'go test'. See 'go help testflag' for details. @@ -133,7 +137,8 @@ control the execution of any test: -covermode set,count,atomic Set the mode for coverage analysis for the package[s] - being tested. The default is "set". + being tested. The default is "set" unless -race is enabled, + in which case it is "atomic". The values: set: bool: does this statement run? count: int: how many times does this statement run? @@ -168,9 +173,7 @@ control the execution of any test: Enable more precise (and expensive) memory profiles by setting runtime.MemProfileRate. See 'godoc runtime MemProfileRate'. To profile all memory allocations, use -test.memprofilerate=1 - and set the environment variable GOGC=off to disable the - garbage collector, provided the test can run in the available - memory without garbage collection. + and pass --alloc_space flag to the pprof tool. -outputdir directory Place output files from profiling in the specified directory, @@ -273,7 +276,6 @@ var ( testCoverPkgs []*Package // -coverpkg flag testProfile bool // some profiling flag testNeedBinary bool // profile needs to keep binary around - testI bool // -i flag testV bool // -v flag testFiles []string // -file flag(s) TODO: not respected testTimeout string // -timeout flag @@ -295,6 +297,8 @@ func runTest(cmd *Command, args []string) { var pkgArgs []string pkgArgs, testArgs = testFlags(args) + findExecCmd() // initialize cached result + raceInit() pkgs := packagesForBuild(pkgArgs) if len(pkgs) == 0 { @@ -334,7 +338,7 @@ func runTest(cmd *Command, args []string) { var b builder b.init() - if testI { + if buildI { buildV = testV deps := make(map[string]bool) @@ -411,7 +415,11 @@ func runTest(cmd *Command, args []string) { p.Stale = true // rebuild p.fake = true // do not warn about rebuild p.coverMode = testCoverMode - p.coverVars = declareCoverVars(p.ImportPath, p.GoFiles...) + var coverFiles []string + coverFiles = append(coverFiles, p.GoFiles...) + coverFiles = append(coverFiles, p.CgoFiles...) + coverFiles = append(coverFiles, p.TestGoFiles...) + p.coverVars = declareCoverVars(p.ImportPath, coverFiles...) } } @@ -516,7 +524,7 @@ func contains(x []string, s string) bool { func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, err error) { if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 { - build := &action{p: p} + build := b.action(modeBuild, modeBuild, p) run := &action{p: p, deps: []*action{build}} print := &action{f: (*builder).notest, p: p, deps: []*action{run}} return build, run, print, nil @@ -530,16 +538,31 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, var imports, ximports []*Package var stk importStack - stk.push(p.ImportPath + "_test") + stk.push(p.ImportPath + " (test)") for _, path := range p.TestImports { p1 := loadImport(path, p.Dir, &stk, p.build.TestImportPos[path]) if p1.Error != nil { return nil, nil, nil, p1.Error } + if contains(p1.Deps, p.ImportPath) { + // Same error that loadPackage returns (via reusePackage) in pkg.go. + // Can't change that code, because that code is only for loading the + // non-test copy of a package. + err := &PackageError{ + ImportStack: testImportStack(stk[0], p1, p.ImportPath), + Err: "import cycle not allowed in test", + isImportCycle: true, + } + return nil, nil, nil, err + } imports = append(imports, p1) } + stk.pop() + stk.push(p.ImportPath + "_test") + pxtestNeedsPtest := false for _, path := range p.XTestImports { if path == p.ImportPath { + pxtestNeedsPtest = true continue } p1 := loadImport(path, p.Dir, &stk, p.build.XTestImportPos[path]) @@ -618,7 +641,10 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, if localCover { ptest.coverMode = testCoverMode - ptest.coverVars = declareCoverVars(ptest.ImportPath, ptest.GoFiles...) + var coverFiles []string + coverFiles = append(coverFiles, ptest.GoFiles...) + coverFiles = append(coverFiles, ptest.CgoFiles...) + ptest.coverVars = declareCoverVars(ptest.ImportPath, coverFiles...) } } else { ptest = p @@ -637,11 +663,14 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, build: &build.Package{ ImportPos: p.build.XTestImportPos, }, - imports: append(ximports, ptest), + imports: ximports, pkgdir: testDir, fake: true, Stale: true, } + if pxtestNeedsPtest { + pxtest.imports = append(pxtest.imports, ptest) + } } // Action for building pkg.test. @@ -651,21 +680,20 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, GoFiles: []string{"_testmain.go"}, ImportPath: "testmain", Root: p.Root, - imports: []*Package{ptest}, build: &build.Package{Name: "main"}, pkgdir: testDir, fake: true, Stale: true, - } - if pxtest != nil { - pmain.imports = append(pmain.imports, pxtest) + omitDWARF: !testC && !testNeedBinary, } // The generated main also imports testing and regexp. stk.push("testmain") for dep := range testMainDeps { - if ptest.ImportPath != dep { - p1 := loadImport("testing", "", &stk, nil) + if dep == ptest.ImportPath { + pmain.imports = append(pmain.imports, ptest) + } else { + p1 := loadImport(dep, "", &stk, nil) if p1.Error != nil { return nil, nil, nil, p1.Error } @@ -687,6 +715,21 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, } } + // Do initial scan for metadata needed for writing _testmain.go + // Use that metadata to update the list of imports for package main. + // The list of imports is used by recompileForTest and by the loop + // afterward that gathers t.Cover information. + t, err := loadTestFuncs(ptest) + if err != nil { + return nil, nil, nil, err + } + if t.NeedTest || ptest.coverMode != "" { + pmain.imports = append(pmain.imports, ptest) + } + if t.NeedXtest { + pmain.imports = append(pmain.imports, pxtest) + } + if ptest != p && localCover { // We have made modifications to the package p being tested // and are rebuilding p (as ptest), writing it to the testDir tree. @@ -703,7 +746,15 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, recompileForTest(pmain, p, ptest, testDir) } - if err := writeTestmain(filepath.Join(testDir, "_testmain.go"), pmain, ptest); err != nil { + for _, cp := range pmain.imports { + if len(cp.coverVars) > 0 { + t.Cover = append(t.Cover, coverInfo{cp, cp.coverVars}) + } + } + + // writeTestmain writes _testmain.go. This must happen after recompileForTest, + // because recompileForTest modifies XXX. + if err := writeTestmain(filepath.Join(testDir, "_testmain.go"), t); err != nil { return nil, nil, nil, err } @@ -711,7 +762,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, if ptest != p { a := b.action(modeBuild, modeBuild, ptest) - a.objdir = testDir + string(filepath.Separator) + a.objdir = testDir + string(filepath.Separator) + "_obj_test" + string(filepath.Separator) a.objpkg = ptestObj a.target = ptestObj a.link = false @@ -719,7 +770,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, if pxtest != nil { a := b.action(modeBuild, modeBuild, pxtest) - a.objdir = testDir + string(filepath.Separator) + a.objdir = testDir + string(filepath.Separator) + "_obj_xtest" + string(filepath.Separator) a.objpkg = buildToolchain.pkgpath(testDir, pxtest) a.target = a.objpkg } @@ -765,6 +816,24 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, return pmainAction, runAction, printAction, nil } +func testImportStack(top string, p *Package, target string) []string { + stk := []string{top, p.ImportPath} +Search: + for p.ImportPath != target { + for _, p1 := range p.imports { + if p1.ImportPath == target || contains(p1.Deps, target) { + stk = append(stk, p1.ImportPath) + p = p1 + continue Search + } + } + // Can't happen, but in case it does... + stk = append(stk, "") + break + } + return stk +} + func recompileForTest(pmain, preal, ptest *Package, testDir string) { // The "test copy" of preal is ptest. // For each package that depends on preal, make a "test copy" @@ -836,7 +905,7 @@ func declareCoverVars(importPath string, files ...string) map[string]*CoverVar { // runTest is the action for running a test binary. func (b *builder) runTest(a *action) error { - args := stringList(a.deps[0].target, testArgs) + args := stringList(findExecCmd(), a.deps[0].target, testArgs) a.testOutput = new(bytes.Buffer) if buildN || buildX { @@ -1007,31 +1076,26 @@ type coverInfo struct { Vars map[string]*CoverVar } -// writeTestmain writes the _testmain.go file for package p to -// the file named out. -func writeTestmain(out string, pmain, p *Package) error { - var cover []coverInfo - for _, cp := range pmain.imports { - if len(cp.coverVars) > 0 { - cover = append(cover, coverInfo{cp, cp.coverVars}) - } - } - +// loadTestFuncs returns the testFuncs describing the tests that will be run. +func loadTestFuncs(ptest *Package) (*testFuncs, error) { t := &testFuncs{ - Package: p, - Cover: cover, + Package: ptest, } - for _, file := range p.TestGoFiles { - if err := t.load(filepath.Join(p.Dir, file), "_test", &t.NeedTest); err != nil { - return err + for _, file := range ptest.TestGoFiles { + if err := t.load(filepath.Join(ptest.Dir, file), "_test", &t.NeedTest); err != nil { + return nil, err } } - for _, file := range p.XTestGoFiles { - if err := t.load(filepath.Join(p.Dir, file), "_xtest", &t.NeedXtest); err != nil { - return err + for _, file := range ptest.XTestGoFiles { + if err := t.load(filepath.Join(ptest.Dir, file), "_xtest", &t.NeedXtest); err != nil { + return nil, err } } + return t, nil +} +// writeTestmain writes the _testmain.go file for t to the file named out. +func writeTestmain(out string, t *testFuncs) error { f, err := os.Create(out) if err != nil { return err diff --git a/src/cmd/go/testdata/cgocover/p.go b/src/cmd/go/testdata/cgocover/p.go new file mode 100644 index 000000000..a6a3891cd --- /dev/null +++ b/src/cmd/go/testdata/cgocover/p.go @@ -0,0 +1,19 @@ +package p + +/* +void +f(void) +{ +} +*/ +import "C" + +var b bool + +func F() { + if b { + for { + } + } + C.f() +} diff --git a/src/cmd/go/testdata/cgocover/p_test.go b/src/cmd/go/testdata/cgocover/p_test.go new file mode 100644 index 000000000..a8f057e35 --- /dev/null +++ b/src/cmd/go/testdata/cgocover/p_test.go @@ -0,0 +1,7 @@ +package p + +import "testing" + +func TestF(t *testing.T) { + F() +} diff --git a/src/cmd/go/testdata/dep_test.go b/src/cmd/go/testdata/dep_test.go new file mode 100644 index 000000000..0c53ac4f9 --- /dev/null +++ b/src/cmd/go/testdata/dep_test.go @@ -0,0 +1,7 @@ +// Copyright 2014 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 deps + +import _ "testing" diff --git a/src/cmd/go/testdata/src/notest/hello.go b/src/cmd/go/testdata/src/notest/hello.go new file mode 100644 index 000000000..7c42c32fb --- /dev/null +++ b/src/cmd/go/testdata/src/notest/hello.go @@ -0,0 +1,6 @@ +package notest + +func hello() { + println("hello world") +} +Hello world diff --git a/src/cmd/go/testdata/src/testcycle/p1/p1.go b/src/cmd/go/testdata/src/testcycle/p1/p1.go new file mode 100644 index 000000000..65ab76d4e --- /dev/null +++ b/src/cmd/go/testdata/src/testcycle/p1/p1.go @@ -0,0 +1,7 @@ +package p1 + +import _ "testcycle/p2" + +func init() { + println("p1 init") +} diff --git a/src/cmd/go/testdata/src/testcycle/p1/p1_test.go b/src/cmd/go/testdata/src/testcycle/p1/p1_test.go new file mode 100644 index 000000000..75abb13e6 --- /dev/null +++ b/src/cmd/go/testdata/src/testcycle/p1/p1_test.go @@ -0,0 +1,6 @@ +package p1 + +import "testing" + +func Test(t *testing.T) { +} diff --git a/src/cmd/go/testdata/src/testcycle/p2/p2.go b/src/cmd/go/testdata/src/testcycle/p2/p2.go new file mode 100644 index 000000000..7e26cdf19 --- /dev/null +++ b/src/cmd/go/testdata/src/testcycle/p2/p2.go @@ -0,0 +1,7 @@ +package p2 + +import _ "testcycle/p3" + +func init() { + println("p2 init") +} diff --git a/src/cmd/go/testdata/src/testcycle/p3/p3.go b/src/cmd/go/testdata/src/testcycle/p3/p3.go new file mode 100644 index 000000000..bb0a2f4f6 --- /dev/null +++ b/src/cmd/go/testdata/src/testcycle/p3/p3.go @@ -0,0 +1,5 @@ +package p3 + +func init() { + println("p3 init") +} diff --git a/src/cmd/go/testdata/src/testcycle/p3/p3_test.go b/src/cmd/go/testdata/src/testcycle/p3/p3_test.go new file mode 100644 index 000000000..9b4b0757f --- /dev/null +++ b/src/cmd/go/testdata/src/testcycle/p3/p3_test.go @@ -0,0 +1,10 @@ +package p3 + +import ( + "testing" + + _ "testcycle/p1" +) + +func Test(t *testing.T) { +} diff --git a/src/cmd/go/testdata/src/xtestonly/f.go b/src/cmd/go/testdata/src/xtestonly/f.go new file mode 100644 index 000000000..dac039e1a --- /dev/null +++ b/src/cmd/go/testdata/src/xtestonly/f.go @@ -0,0 +1,3 @@ +package xtestonly + +func F() int { return 42 } diff --git a/src/cmd/go/testdata/src/xtestonly/f_test.go b/src/cmd/go/testdata/src/xtestonly/f_test.go new file mode 100644 index 000000000..01f6e8373 --- /dev/null +++ b/src/cmd/go/testdata/src/xtestonly/f_test.go @@ -0,0 +1,12 @@ +package xtestonly_test + +import ( + "testing" + "xtestonly" +) + +func TestF(t *testing.T) { + if x := xtestonly.F(); x != 42 { + t.Errorf("f.F() = %d, want 42", x) + } +} diff --git a/src/cmd/go/testdata/standalone_test.go b/src/cmd/go/testdata/standalone_test.go new file mode 100644 index 000000000..59cf918b9 --- /dev/null +++ b/src/cmd/go/testdata/standalone_test.go @@ -0,0 +1,6 @@ +package standalone_test + +import "testing" + +func Test(t *testing.T) { +} diff --git a/src/cmd/go/testdata/testonly/p_test.go b/src/cmd/go/testdata/testonly/p_test.go new file mode 100644 index 000000000..c89cd18d0 --- /dev/null +++ b/src/cmd/go/testdata/testonly/p_test.go @@ -0,0 +1 @@ +package p diff --git a/src/cmd/go/testflag.go b/src/cmd/go/testflag.go index aea81d8f8..73f311e5f 100644 --- a/src/cmd/go/testflag.go +++ b/src/cmd/go/testflag.go @@ -66,7 +66,6 @@ var testFlagDefn = []*testFlagSpec{ // local. {name: "c", boolVar: &testC}, {name: "file", multiOK: true}, - {name: "i", boolVar: &testI}, {name: "cover", boolVar: &testCover}, {name: "coverpkg"}, @@ -75,8 +74,11 @@ var testFlagDefn = []*testFlagSpec{ {name: "n", boolVar: &buildN}, {name: "p"}, {name: "x", boolVar: &buildX}, + {name: "i", boolVar: &buildI}, {name: "work", boolVar: &buildWork}, + {name: "ccflags"}, {name: "gcflags"}, + {name: "exec"}, {name: "ldflags"}, {name: "gccgoflags"}, {name: "tags"}, @@ -116,7 +118,6 @@ var testFlagDefn = []*testFlagSpec{ func testFlags(args []string) (packageNames, passToTest []string) { inPkg := false outputDir := "" - testCoverMode = "set" for i := 0; i < len(args); i++ { if !strings.HasPrefix(args[i], "-") { if !inPkg && packageNames == nil { @@ -154,6 +155,16 @@ func testFlags(args []string) (packageNames, passToTest []string) { setBoolFlag(f.boolVar, value) case "p": setIntFlag(&buildP, value) + case "exec": + execCmd, err = splitQuotedFields(value) + if err != nil { + fatalf("invalid flag argument for -%s: %v", f.name, err) + } + case "ccflags": + buildCcflags, err = splitQuotedFields(value) + if err != nil { + fatalf("invalid flag argument for -%s: %v", f.name, err) + } case "gcflags": buildGcflags, err = splitQuotedFields(value) if err != nil { @@ -212,6 +223,14 @@ func testFlags(args []string) (packageNames, passToTest []string) { } } + if testCoverMode == "" { + testCoverMode = "set" + if buildRace { + // Default coverage mode is atomic when -race is set. + testCoverMode = "atomic" + } + } + // Tell the test what directory we're running in, so it can write the profiles there. if testProfile && outputDir == "" { dir, err := os.Getwd() diff --git a/src/cmd/go/vcs.go b/src/cmd/go/vcs.go index 22d5ebc24..8f0bae0b7 100644 --- a/src/cmd/go/vcs.go +++ b/src/cmd/go/vcs.go @@ -354,6 +354,8 @@ type repoRoot struct { root string } +var httpPrefixRE = regexp.MustCompile(`^https?:`) + // repoRootForImportPath analyzes importPath to determine the // version control system, and code repository to use. func repoRootForImportPath(importPath string) (*repoRoot, error) { @@ -390,8 +392,12 @@ var errUnknownSite = errors.New("dynamic lookup required to find mapping") // // If scheme is non-empty, that scheme is forced. func repoRootForImportPathStatic(importPath, scheme string) (*repoRoot, error) { - if strings.Contains(importPath, "://") { - return nil, fmt.Errorf("invalid import path %q", importPath) + // A common error is to use https://packagepath because that's what + // hg and git require. Diagnose this helpfully. + if loc := httpPrefixRE.FindStringIndex(importPath); loc != nil { + // The importPath has been cleaned, so has only one slash. The pattern + // ignores the slashes; the error message puts them back on the RHS at least. + return nil, fmt.Errorf("%q not allowed in import path", importPath[loc[0]:loc[1]]+"//") } for _, srv := range vcsPaths { if !strings.HasPrefix(importPath, srv.prefix) { diff --git a/src/cmd/gofmt/doc.go b/src/cmd/gofmt/doc.go index 94e67fd89..8f73ef5b9 100644 --- a/src/cmd/gofmt/doc.go +++ b/src/cmd/gofmt/doc.go @@ -4,6 +4,7 @@ /* Gofmt formats Go programs. +It uses tabs (width = 8) for indentation and blanks for alignment. Without an explicit path, it processes the standard input. Given a file, it operates on that file; given a directory, it operates on all .go files in @@ -33,13 +34,9 @@ The flags are: If a file's formatting is different from gofmt's, overwrite it with gofmt's version. -Formatting control flags: - -comments=true - Print comments; if false, all comments are elided from the output. - -tabs=true - Indent with tabs; if false, spaces are used instead. - -tabwidth=8 - Tab width in spaces. +Debugging support: + -cpuprofile filename + Write cpu profile to the specified file. The rewrite rule specified with the -r flag must be a string of the form: diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go index 861ff9390..576cae522 100644 --- a/src/cmd/gofmt/gofmt.go +++ b/src/cmd/gofmt/gofmt.go @@ -31,21 +31,20 @@ var ( doDiff = flag.Bool("d", false, "display diffs instead of rewriting files") allErrors = flag.Bool("e", false, "report all errors (not just the first 10 on different lines)") - // layout control - comments = flag.Bool("comments", true, "print comments") - tabWidth = flag.Int("tabwidth", 8, "tab width") - tabIndent = flag.Bool("tabs", true, "indent with tabs") - // debugging cpuprofile = flag.String("cpuprofile", "", "write cpu profile to this file") ) +const ( + tabWidth = 8 + printerMode = printer.UseSpaces | printer.TabIndent +) + var ( - fileSet = token.NewFileSet() // per process FileSet - exitCode = 0 - rewrite func(*ast.File) *ast.File - parserMode parser.Mode - printerMode printer.Mode + fileSet = token.NewFileSet() // per process FileSet + exitCode = 0 + rewrite func(*ast.File) *ast.File + parserMode parser.Mode ) func report(err error) { @@ -60,22 +59,12 @@ func usage() { } func initParserMode() { - parserMode = parser.Mode(0) - if *comments { - parserMode |= parser.ParseComments - } + parserMode = parser.ParseComments if *allErrors { parserMode |= parser.AllErrors } } -func initPrinterMode() { - printerMode = printer.UseSpaces - if *tabIndent { - printerMode |= printer.TabIndent - } -} - func isGoFile(f os.FileInfo) bool { // ignore non-Go files name := f.Name() @@ -118,7 +107,7 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error } var buf bytes.Buffer - err = (&printer.Config{Mode: printerMode, Tabwidth: *tabWidth}).Fprint(&buf, fileSet, file) + err = (&printer.Config{Mode: printerMode, Tabwidth: tabWidth}).Fprint(&buf, fileSet, file) if err != nil { return err } @@ -180,11 +169,6 @@ func main() { func gofmtMain() { flag.Usage = usage flag.Parse() - if *tabWidth < 0 { - fmt.Fprintf(os.Stderr, "negative tabwidth %d\n", *tabWidth) - exitCode = 2 - return - } if *cpuprofile != "" { f, err := os.Create(*cpuprofile) @@ -199,7 +183,6 @@ func gofmtMain() { } initParserMode() - initPrinterMode() initRewrite() if flag.NArg() == 0 { diff --git a/src/cmd/gofmt/gofmt_test.go b/src/cmd/gofmt/gofmt_test.go index 75a322a6c..b9335b8f3 100644 --- a/src/cmd/gofmt/gofmt_test.go +++ b/src/cmd/gofmt/gofmt_test.go @@ -40,7 +40,6 @@ func runTest(t *testing.T, in, out, flags string) { } initParserMode() - initPrinterMode() initRewrite() var buf bytes.Buffer diff --git a/src/cmd/gofmt/long_test.go b/src/cmd/gofmt/long_test.go index 862e9d987..108278b33 100644 --- a/src/cmd/gofmt/long_test.go +++ b/src/cmd/gofmt/long_test.go @@ -38,7 +38,7 @@ func gofmt(fset *token.FileSet, filename string, src *bytes.Buffer) error { } ast.SortImports(fset, f) src.Reset() - return (&printer.Config{Mode: printerMode, Tabwidth: *tabWidth}).Fprint(src, fset, f) + return (&printer.Config{Mode: printerMode, Tabwidth: tabWidth}).Fprint(src, fset, f) } func testFile(t *testing.T, b1, b2 *bytes.Buffer, filename string) { diff --git a/src/cmd/gofmt/rewrite.go b/src/cmd/gofmt/rewrite.go index 66d2331a5..fb6c6fc81 100644 --- a/src/cmd/gofmt/rewrite.go +++ b/src/cmd/gofmt/rewrite.go @@ -48,7 +48,7 @@ func parseExpr(s, what string) ast.Expr { /* func dump(msg string, val reflect.Value) { fmt.Printf("%s:\n", msg) - ast.Print(fset, val.Interface()) + ast.Print(fileSet, val.Interface()) fmt.Println() } */ @@ -59,8 +59,9 @@ func rewriteFile(pattern, replace ast.Expr, p *ast.File) *ast.File { m := make(map[string]reflect.Value) pat := reflect.ValueOf(pattern) repl := reflect.ValueOf(replace) - var f func(val reflect.Value) reflect.Value // f is recursive - f = func(val reflect.Value) reflect.Value { + + var rewriteVal func(val reflect.Value) reflect.Value + rewriteVal = func(val reflect.Value) reflect.Value { // don't bother if val is invalid to start with if !val.IsValid() { return reflect.Value{} @@ -68,22 +69,22 @@ func rewriteFile(pattern, replace ast.Expr, p *ast.File) *ast.File { for k := range m { delete(m, k) } - val = apply(f, val) + val = apply(rewriteVal, val) if match(m, pat, val) { val = subst(m, repl, reflect.ValueOf(val.Interface().(ast.Node).Pos())) } return val } - r := apply(f, reflect.ValueOf(p)).Interface().(*ast.File) + + r := apply(rewriteVal, reflect.ValueOf(p)).Interface().(*ast.File) r.Comments = cmap.Filter(r).Comments() // recreate comments list return r } -// 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) { - // don't bother if y is invalid to start with - if !y.IsValid() { +// set is a wrapper for x.Set(y); it protects the caller from panics if x cannot be changed to y. +func set(x, y reflect.Value) { + // don't bother if x cannot be set or y is invalid + if !x.CanSet() || !y.IsValid() { return } defer func() { @@ -134,16 +135,16 @@ func apply(f func(reflect.Value) reflect.Value, val reflect.Value) reflect.Value case reflect.Slice: for i := 0; i < v.Len(); i++ { e := v.Index(i) - setValue(e, f(e)) + set(e, f(e)) } case reflect.Struct: for i := 0; i < v.NumField(); i++ { e := v.Field(i) - setValue(e, f(e)) + set(e, f(e)) } case reflect.Interface: e := v.Elem() - setValue(v, f(e)) + set(v, f(e)) } return val } diff --git a/src/cmd/gofmt/testdata/typeswitch.golden b/src/cmd/gofmt/testdata/typeswitch.golden index 87e916181..2b1905edd 100644 --- a/src/cmd/gofmt/testdata/typeswitch.golden +++ b/src/cmd/gofmt/testdata/typeswitch.golden @@ -4,7 +4,7 @@ into the correct unparenthesized form. Only type-switches that didn't declare a variable - in the the type switch type assertion and which + in the type switch type assertion and which contained only "expression-like" (named) types in their cases were permitted to have their type assertion parenthesized by go/parser (due to a weak predicate in the parser). All others diff --git a/src/cmd/gofmt/testdata/typeswitch.input b/src/cmd/gofmt/testdata/typeswitch.input index f90f28949..8f8cba9b8 100644 --- a/src/cmd/gofmt/testdata/typeswitch.input +++ b/src/cmd/gofmt/testdata/typeswitch.input @@ -4,7 +4,7 @@ into the correct unparenthesized form. Only type-switches that didn't declare a variable - in the the type switch type assertion and which + in the type switch type assertion and which contained only "expression-like" (named) types in their cases were permitted to have their type assertion parenthesized by go/parser (due to a weak predicate in the parser). All others diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c index 30d7c8185..55d020710 100644 --- a/src/cmd/ld/data.c +++ b/src/cmd/ld/data.c @@ -38,15 +38,14 @@ #include "../../pkg/runtime/mgc0.h" void dynreloc(void); -static vlong addaddrplus4(Sym *s, Sym *t, vlong add); /* * divide-and-conquer list-link - * sort of Sym* structures. + * sort of LSym* structures. * Used for the data block. */ int -datcmp(Sym *s1, Sym *s2) +datcmp(LSym *s1, LSym *s2) { if(s1->type != s2->type) return (int)s1->type - (int)s2->type; @@ -58,11 +57,11 @@ datcmp(Sym *s1, Sym *s2) return strcmp(s1->name, s2->name); } -Sym* -listsort(Sym *l, int (*cmp)(Sym*, Sym*), int off) +LSym* +listsort(LSym *l, int (*cmp)(LSym*, LSym*), int off) { - Sym *l1, *l2, *le; - #define NEXT(l) (*(Sym**)((char*)(l)+off)) + LSym *l1, *l2, *le; + #define NEXT(l) (*(LSym**)((char*)(l)+off)) if(l == 0 || NEXT(l) == 0) return l; @@ -128,32 +127,16 @@ listsort(Sym *l, int (*cmp)(Sym*, Sym*), int off) #undef NEXT } -Reloc* -addrel(Sym *s) -{ - if(s->nr >= s->maxr) { - if(s->maxr == 0) - s->maxr = 4; - else - s->maxr <<= 1; - s->r = erealloc(s->r, s->maxr*sizeof s->r[0]); - memset(s->r+s->nr, 0, (s->maxr-s->nr)*sizeof s->r[0]); - } - return &s->r[s->nr++]; -} - void -relocsym(Sym *s) +relocsym(LSym *s) { Reloc *r; - Sym *rs; - Prog p; + LSym *rs; int32 i, off, siz, fl; vlong o; uchar *cast; - cursym = s; - memset(&p, 0, sizeof p); + ctxt->cursym = s; for(r=s->r; rr+s->nr; r++) { r->done = 1; off = r->off; @@ -168,10 +151,12 @@ relocsym(Sym *s) } if(r->type >= 256) continue; + if(r->siz == 0) // informational relocation - no work to do + continue; - if(r->sym != S && r->sym->type == SDYNIMPORT) + // Solaris needs the ability to reference dynimport symbols. + if(HEADTYPE != Hsolaris && 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->type != STLSBSS && !r->sym->reachable) diag("unreachable sym in relocation: %s %s", s->name, r->sym->name); @@ -181,13 +166,56 @@ relocsym(Sym *s) if(archreloc(r, s, &o) < 0) diag("unknown reloc %d", r->type); break; - case D_TLS: + case R_TLS: + if(linkmode == LinkInternal && iself && thechar == '5') { + // On ELF ARM, the thread pointer is 8 bytes before + // the start of the thread-local data block, so add 8 + // to the actual TLS offset (r->sym->value). + // This 8 seems to be a fundamental constant of + // ELF on ARM (or maybe Glibc on ARM); it is not + // related to the fact that our own TLS storage happens + // to take up 8 bytes. + o = 8 + r->sym->value; + break; + } r->done = 0; o = 0; if(thechar != '6') o = r->add; break; - case D_ADDR: + case R_TLS_LE: + if(linkmode == LinkExternal && iself && HEADTYPE != Hopenbsd) { + r->done = 0; + r->sym = ctxt->gmsym; + r->xsym = ctxt->gmsym; + r->xadd = r->add; + o = 0; + if(thechar != '6') + o = r->add; + break; + } + o = ctxt->tlsoffset + r->add; + break; + + case R_TLS_IE: + if(linkmode == LinkExternal && iself && HEADTYPE != Hopenbsd) { + r->done = 0; + r->sym = ctxt->gmsym; + r->xsym = ctxt->gmsym; + r->xadd = r->add; + o = 0; + if(thechar != '6') + o = r->add; + break; + } + if(iself || ctxt->headtype == Hplan9) + o = ctxt->tlsoffset + r->add; + else if(ctxt->headtype == Hwindows) + o = r->add; + else + sysfatal("unexpected R_TLS_IE relocation for %s", headstr(ctxt->headtype)); + break; + case R_ADDR: if(linkmode == LinkExternal && r->sym->type != SCONST) { r->done = 0; @@ -198,7 +226,7 @@ relocsym(Sym *s) r->xadd += symaddr(rs) - symaddr(rs->outer); rs = rs->outer; } - if(rs->type != SHOSTOBJ && rs->sect == nil) + if(rs->type != SHOSTOBJ && rs->type != SDYNIMPORT && rs->sect == nil) diag("missing section for %s", rs->name); r->xsym = rs; @@ -210,15 +238,26 @@ relocsym(Sym *s) if(rs->type != SHOSTOBJ) o += symaddr(rs); } else { - diag("unhandled pcrel relocation for %s", headtype); + diag("unhandled pcrel relocation for %s", headstring); } break; } o = symaddr(r->sym) + r->add; + + // On amd64, 4-byte offsets will be sign-extended, so it is impossible to + // access more than 2GB of static data; fail at link time is better than + // fail at runtime. See http://golang.org/issue/7980. + // Instead of special casing only amd64, we treat this as an error on all + // 64-bit architectures so as to be future-proof. + if((int32)o < 0 && PtrSize > 4 && siz == 4) { + diag("non-pc-relative relocation address is too big: %#llux", o); + errorexit(); + } break; - case D_PCREL: + case R_CALL: + case R_PCREL: // r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call. - if(linkmode == LinkExternal && r->sym && r->sym->type != SCONST && r->sym->sect != cursym->sect) { + if(linkmode == LinkExternal && r->sym && r->sym->type != SCONST && r->sym->sect != ctxt->cursym->sect) { r->done = 0; // set up addend for eventual relocation via outer symbol. @@ -229,7 +268,7 @@ relocsym(Sym *s) rs = rs->outer; } r->xadd -= r->siz; // relative to address after the relocated chunk - if(rs->type != SHOSTOBJ && rs->sect == nil) + if(rs->type != SHOSTOBJ && rs->type != SDYNIMPORT && rs->sect == nil) diag("missing section for %s", rs->name); r->xsym = rs; @@ -242,7 +281,7 @@ relocsym(Sym *s) o += symaddr(rs) - rs->sect->vaddr; o -= r->off; // WTF? } else { - diag("unhandled pcrel relocation for %s", headtype); + diag("unhandled pcrel relocation for %s", headstring); } break; } @@ -257,17 +296,21 @@ relocsym(Sym *s) // the standard host compiler (gcc on most other systems). o += r->add - (s->value + r->off + (int32)r->siz); break; - case D_SIZE: + case R_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 : "", (void*)symaddr(r->sym), (void*)s->value, (void*)r->off, (void*)r->siz, (void*)o); +//print("relocate %s %#llux (%#llux+%#llux, size %d) => %s %#llux +%#llx [%llx]\n", s->name, (uvlong)(s->value+off), (uvlong)s->value, (uvlong)r->off, r->siz, r->sym ? r->sym->name : "", (uvlong)symaddr(r->sym), (vlong)r->add, (vlong)o); switch(siz) { default: - cursym = s; + ctxt->cursym = s; diag("bad reloc size %#ux for %s", siz, r->sym->name); + case 1: + // TODO(rsc): Remove. + s->p[off] = (int8)o; + break; case 4: - if(r->type == D_PCREL) { + if(r->type == R_PCREL || r->type == R_CALL) { if(o != (int32)o) diag("pc-relative relocation address is too big: %#llx", o); } else { @@ -291,31 +334,35 @@ relocsym(Sym *s) void reloc(void) { - Sym *s; + LSym *s; if(debug['v']) Bprint(&bso, "%5.2f reloc\n", cputime()); Bflush(&bso); - for(s=textp; s!=S; s=s->next) + for(s=ctxt->textp; s!=S; s=s->next) relocsym(s); for(s=datap; s!=S; s=s->next) relocsym(s); } void -dynrelocsym(Sym *s) +dynrelocsym(LSym *s) { Reloc *r; - + if(HEADTYPE == Hwindows) { - Sym *rel, *targ; + LSym *rel, *targ; - rel = lookup(".rel", 0); + rel = linklookup(ctxt, ".rel", 0); if(s == rel) return; for(r=s->r; rr+s->nr; r++) { targ = r->sym; + if(targ == nil) + continue; + if(!targ->reachable) + diag("internal inconsistency: dynamic symbol %s is not reachable.", targ->name); if(r->sym->plt == -2 && r->sym->got != -2) { // make dynimport JMP table for PE object files. targ->plt = rel->size; r->sym = rel; @@ -323,17 +370,17 @@ dynrelocsym(Sym *s) // jmp *addr if(thechar == '8') { - adduint8(rel, 0xff); - adduint8(rel, 0x25); - addaddr(rel, targ); - adduint8(rel, 0x90); - adduint8(rel, 0x90); + adduint8(ctxt, rel, 0xff); + adduint8(ctxt, rel, 0x25); + addaddr(ctxt, rel, targ); + adduint8(ctxt, rel, 0x90); + adduint8(ctxt, rel, 0x90); } else { - adduint8(rel, 0xff); - adduint8(rel, 0x24); - adduint8(rel, 0x25); - addaddrplus4(rel, targ, 0); - adduint8(rel, 0x90); + adduint8(ctxt, rel, 0xff); + adduint8(ctxt, rel, 0x24); + adduint8(ctxt, rel, 0x25); + addaddrplus4(ctxt, rel, targ, 0); + adduint8(ctxt, rel, 0x90); } } else if(r->sym->plt >= 0) { r->sym = rel; @@ -344,15 +391,18 @@ dynrelocsym(Sym *s) } for(r=s->r; rr+s->nr; r++) { - if(r->sym != S && r->sym->type == SDYNIMPORT || r->type >= 256) + if(r->sym != S && r->sym->type == SDYNIMPORT || r->type >= 256) { + if(r->sym != S && !r->sym->reachable) + diag("internal inconsistency: dynamic symbol %s is not reachable.", r->sym->name); adddynrel(s, r); + } } } void dynreloc(void) { - Sym *s; + LSym *s; // -d suppresses dynamic loader format, so we may as well not // compute these sections or mark their symbols as reachable. @@ -362,7 +412,7 @@ dynreloc(void) Bprint(&bso, "%5.2f reloc\n", cputime()); Bflush(&bso); - for(s=textp; s!=S; s=s->next) + for(s=ctxt->textp; s!=S; s=s->next) dynrelocsym(s); for(s=datap; s!=S; s=s->next) dynrelocsym(s); @@ -370,118 +420,10 @@ dynreloc(void) elfdynhash(); } -void -symgrow(Sym *s, int32 siz) -{ - if(s->np >= siz) - return; - - if(s->np > s->maxp) { - cursym = s; - diag("corrupt symbol data: np=%lld > maxp=%lld", (vlong)s->np, (vlong)s->maxp); - errorexit(); - } - - if(s->maxp < siz) { - if(s->maxp == 0) - s->maxp = 8; - while(s->maxp < siz) - s->maxp <<= 1; - s->p = erealloc(s->p, s->maxp); - memset(s->p+s->np, 0, s->maxp-s->np); - } - s->np = siz; -} - -void -savedata(Sym *s, Prog *p, char *pn) -{ - int32 off, siz, i, fl; - uchar *cast; - vlong o; - Reloc *r; - - off = p->from.offset; - siz = p->datasize; - if(off < 0 || siz < 0 || off >= 1<<30 || siz >= 100) - mangle(pn); - 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; ip[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 *start, int32 addr, int32 size) +blk(LSym *start, int32 addr, int32 size) { - Sym *sym; + LSym *sym; int32 eaddr; uchar *p, *ep; @@ -499,7 +441,7 @@ blk(Sym *start, int32 addr, int32 size) diag("phase error: addr=%#llx but sym=%#llx type=%d", (vlong)addr, (vlong)sym->value, sym->type); errorexit(); } - cursym = sym; + ctxt->cursym = sym; for(; addr < sym->value; addr++) cput(0); p = sym->p; @@ -523,21 +465,20 @@ blk(Sym *start, int32 addr, int32 size) void codeblk(int32 addr, int32 size) { - Sym *sym; - int32 eaddr, n, epc; - Prog *p; + LSym *sym; + int32 eaddr, n; uchar *q; if(debug['a']) Bprint(&bso, "codeblk [%#x,%#x) at offset %#llx\n", addr, addr+size, cpos()); - blk(textp, addr, size); + blk(ctxt->textp, addr, size); /* again for printing */ if(!debug['a']) return; - for(sym = textp; sym != nil; sym = sym->next) { + for(sym = ctxt->textp; sym != nil; sym = sym->next) { if(!sym->reachable) continue; if(sym->value >= addr) @@ -557,36 +498,20 @@ codeblk(int32 addr, int32 size) 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, (int)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, "%.6llux\t", (uvlong)p->pc); - q = sym->p + p->pc - sym->value; - n = epc - p->pc; - Bprint(&bso, "%-20.*I | %P\n", (int)n, q, p); - addr += n; + Bprint(&bso, "%.6llux\t%-20s\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, (int)n, q); + addr += n; } if(addr < eaddr) { @@ -600,7 +525,7 @@ codeblk(int32 addr, int32 size) void datblk(int32 addr, int32 size) { - Sym *sym; + LSym *sym; int32 i, eaddr; uchar *p, *ep; char *typ, *rsname; @@ -648,12 +573,15 @@ datblk(int32 addr, int32 size) rsname = r->sym->name; typ = "?"; switch(r->type) { - case D_ADDR: + case R_ADDR: typ = "addr"; break; - case D_PCREL: + case R_PCREL: typ = "pcrel"; break; + case R_CALL: + typ = "call"; + break; } Bprint(&bso, "\treloc %.8ux/%d %s %s+%#llx [%#llx]\n", (uint)(sym->value+r->off), r->siz, typ, rsname, (vlong)r->add, (vlong)(r->sym->value+r->add)); @@ -682,28 +610,28 @@ strnput(char *s, int n) void addstrdata(char *name, char *value) { - Sym *s, *sp; + LSym *s, *sp; char *p; p = smprint("%s.str", name); - sp = lookup(p, 0); + sp = linklookup(ctxt, p, 0); free(p); addstring(sp, value); - s = lookup(name, 0); + s = linklookup(ctxt, name, 0); s->size = 0; s->dupok = 1; - addaddr(s, sp); - adduint32(s, strlen(value)); + addaddr(ctxt, s, sp); + adduint32(ctxt, s, strlen(value)); if(PtrSize == 8) - adduint32(s, 0); // round struct to pointer width + adduint32(ctxt, s, 0); // round struct to pointer width // in case reachability has already been computed sp->reachable = s->reachable; } vlong -addstring(Sym *s, char *str) +addstring(LSym *s, char *str) { int n; int32 r; @@ -715,230 +643,18 @@ addstring(Sym *s, char *str) n = strlen(str)+1; if(strcmp(s->name, ".shstrtab") == 0) elfsetstring(str, r); - symgrow(s, r+n); + symgrow(ctxt, s, r+n); memmove(s->p+r, str, n); s->size += n; return r; } -vlong -setuintxx(Sym *s, vlong off, uint64 v, vlong wid) -{ - int32 i, fl; - vlong o; - uchar *cast; - - if(s->type == 0) - s->type = SDATA; - s->reachable = 1; - if(s->size < off+wid) { - s->size = off+wid; - symgrow(s, s->size); - } - fl = v; - cast = (uchar*)&fl; - switch(wid) { - 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: - o = v; - cast = (uchar*)&o; - for(i=0; i<8; i++) - s->p[off+i] = cast[inuxi8[i]]; - break; - } - return off+wid; -} - -vlong -adduintxx(Sym *s, uint64 v, int wid) -{ - vlong off; - - off = s->size; - setuintxx(s, off, v, wid); - return off; -} - -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 -setuint8(Sym *s, vlong r, uint8 v) -{ - return setuintxx(s, r, v, 1); -} - -vlong -setuint16(Sym *s, vlong r, uint16 v) -{ - return setuintxx(s, r, v, 2); -} - -vlong -setuint32(Sym *s, vlong r, uint32 v) -{ - return setuintxx(s, r, v, 4); -} - -vlong -setuint64(Sym *s, vlong r, uint64 v) -{ - return setuintxx(s, r, v, 8); -} - -vlong -addaddrplus(Sym *s, Sym *t, vlong 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 + r->siz; -} - -static vlong -addaddrplus4(Sym *s, Sym *t, vlong 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->siz = 4; - r->type = D_ADDR; - r->add = add; - return i + r->siz; -} - -vlong -addpcrelplus(Sym *s, Sym *t, vlong 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 + r->siz; -} - -vlong -addaddr(Sym *s, Sym *t) -{ - return addaddrplus(s, t, 0); -} - -vlong -setaddrplus(Sym *s, vlong off, Sym *t, vlong add) -{ - Reloc *r; - - if(s->type == 0) - s->type = SDATA; - s->reachable = 1; - if(off+PtrSize > s->size) { - s->size = off + PtrSize; - symgrow(s, s->size); - } - r = addrel(s); - r->sym = t; - r->off = off; - r->siz = PtrSize; - r->type = D_ADDR; - r->add = add; - return off + r->siz; -} - -vlong -setaddr(Sym *s, vlong off, Sym *t) -{ - return setaddrplus(s, off, 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 + r->siz; -} - void dosymtype(void) { - Sym *s; + LSym *s; - for(s = allsym; s != nil; s = s->allsym) { + for(s = ctxt->allsym; s != nil; s = s->allsym) { if(s->np > 0) { if(s->type == SBSS) s->type = SDATA; @@ -949,7 +665,7 @@ dosymtype(void) } static int32 -symalign(Sym *s) +symalign(LSym *s) { int32 align; @@ -965,7 +681,7 @@ symalign(Sym *s) } static vlong -aligndatsize(vlong datsize, Sym *s) +aligndatsize(vlong datsize, LSym *s) { return rnd(datsize, symalign(s)); } @@ -973,7 +689,7 @@ aligndatsize(vlong datsize, Sym *s) // maxalign returns the maximum required alignment for // the list of symbols s; the list stops when s->type exceeds type. static int32 -maxalign(Sym *s, int type) +maxalign(LSym *s, int type) { int32 align, max; @@ -987,10 +703,10 @@ maxalign(Sym *s, int type) } static void -gcaddsym(Sym *gc, Sym *s, vlong off) +gcaddsym(LSym *gc, LSym *s, vlong off) { vlong a; - Sym *gotype; + LSym *gotype; if(s->size < PtrSize) return; @@ -1000,22 +716,22 @@ gcaddsym(Sym *gc, Sym *s, vlong off) gotype = s->gotype; if(gotype != nil) { //print("gcaddsym: %s %d %s\n", s->name, s->size, gotype->name); - adduintxx(gc, GC_CALL, PtrSize); - adduintxx(gc, off, PtrSize); - addpcrelplus(gc, decodetype_gc(gotype), 3*PtrSize+4); + adduintxx(ctxt, gc, GC_CALL, PtrSize); + adduintxx(ctxt, gc, off, PtrSize); + addpcrelplus(ctxt, gc, decodetype_gc(gotype), 3*PtrSize+4); if(PtrSize == 8) - adduintxx(gc, 0, 4); + adduintxx(ctxt, gc, 0, 4); } else { //print("gcaddsym: %s %d \n", s->name, s->size); for(a = -off&(PtrSize-1); a+PtrSize<=s->size; a+=PtrSize) { - adduintxx(gc, GC_APTR, PtrSize); - adduintxx(gc, off+a, PtrSize); + adduintxx(ctxt, gc, GC_APTR, PtrSize); + adduintxx(ctxt, gc, off+a, PtrSize); } } } void -growdatsize(vlong *datsizep, Sym *s) +growdatsize(vlong *datsizep, LSym *s) { vlong datsize; @@ -1034,27 +750,30 @@ dodata(void) vlong datsize; Section *sect; Segment *segro; - Sym *s, *last, **l; - Sym *gcdata1, *gcbss1; + LSym *s, *last, **l; + LSym *gcdata1, *gcbss1; if(debug['v']) Bprint(&bso, "%5.2f dodata\n", cputime()); Bflush(&bso); - gcdata1 = lookup("gcdata", 0); - gcbss1 = lookup("gcbss", 0); + gcdata1 = linklookup(ctxt, "gcdata", 0); + gcbss1 = linklookup(ctxt, "gcbss", 0); // size of .data and .bss section. the zero value is later replaced by the actual size of the section. - adduintxx(gcdata1, 0, PtrSize); - adduintxx(gcbss1, 0, PtrSize); + adduintxx(ctxt, gcdata1, 0, PtrSize); + adduintxx(ctxt, gcbss1, 0, PtrSize); last = nil; datap = nil; - for(s=allsym; s!=S; s=s->allsym) { + for(s=ctxt->allsym; s!=S; s=s->allsym) { if(!s->reachable || s->special) continue; if(STEXT < s->type && s->type < SXREF) { + if(s->onlist) + sysfatal("symbol %s listed multiple times", s->name); + s->onlist = 1; if(last == nil) datap = s; else @@ -1092,7 +811,7 @@ dodata(void) } *l = nil; - datap = listsort(datap, datcmp, offsetof(Sym, next)); + datap = listsort(datap, datcmp, offsetof(LSym, next)); /* * allocate sections. list is sorted by type, @@ -1128,8 +847,8 @@ dodata(void) sect->align = maxalign(s, SINITARR-1); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; - lookup("noptrdata", 0)->sect = sect; - lookup("enoptrdata", 0)->sect = sect; + linklookup(ctxt, "noptrdata", 0)->sect = sect; + linklookup(ctxt, "enoptrdata", 0)->sect = sect; for(; s != nil && s->type < SINITARR; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; @@ -1159,11 +878,11 @@ dodata(void) sect->align = maxalign(s, SBSS-1); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; - lookup("data", 0)->sect = sect; - lookup("edata", 0)->sect = sect; + linklookup(ctxt, "data", 0)->sect = sect; + linklookup(ctxt, "edata", 0)->sect = sect; for(; s != nil && s->type < SBSS; s = s->next) { if(s->type == SINITARR) { - cursym = s; + ctxt->cursym = s; diag("unexpected symbol type %d", s->type); } s->sect = sect; @@ -1175,16 +894,16 @@ dodata(void) } sect->len = datsize - sect->vaddr; - adduintxx(gcdata1, GC_END, PtrSize); - setuintxx(gcdata1, 0, sect->len, PtrSize); + adduintxx(ctxt, gcdata1, GC_END, PtrSize); + setuintxx(ctxt, gcdata1, 0, sect->len, PtrSize); /* bss */ sect = addsection(&segdata, ".bss", 06); sect->align = maxalign(s, SNOPTRBSS-1); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; - lookup("bss", 0)->sect = sect; - lookup("ebss", 0)->sect = sect; + linklookup(ctxt, "bss", 0)->sect = sect; + linklookup(ctxt, "ebss", 0)->sect = sect; for(; s != nil && s->type < SNOPTRBSS; s = s->next) { s->sect = sect; datsize = aligndatsize(datsize, s); @@ -1194,16 +913,16 @@ dodata(void) } sect->len = datsize - sect->vaddr; - adduintxx(gcbss1, GC_END, PtrSize); - setuintxx(gcbss1, 0, sect->len, PtrSize); + adduintxx(ctxt, gcbss1, GC_END, PtrSize); + setuintxx(ctxt, gcbss1, 0, sect->len, PtrSize); /* pointer-free bss */ sect = addsection(&segdata, ".noptrbss", 06); sect->align = maxalign(s, SNOPTRBSS); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; - lookup("noptrbss", 0)->sect = sect; - lookup("enoptrbss", 0)->sect = sect; + linklookup(ctxt, "noptrbss", 0)->sect = sect; + linklookup(ctxt, "enoptrbss", 0)->sect = sect; for(; s != nil && s->type == SNOPTRBSS; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; @@ -1211,7 +930,7 @@ dodata(void) growdatsize(&datsize, s); } sect->len = datsize - sect->vaddr; - lookup("end", 0)->sect = sect; + linklookup(ctxt, "end", 0)->sect = sect; // 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits. if(datsize != (uint32)datsize) { @@ -1230,10 +949,18 @@ dodata(void) growdatsize(&datsize, s); } sect->len = datsize; + } else { + // Might be internal linking but still using cgo. + // In that case, the only possible STLSBSS symbol is tlsgm. + // Give it offset 0, because it's the only thing here. + if(s != nil && s->type == STLSBSS && strcmp(s->name, "runtime.tlsgm") == 0) { + s->value = 0; + s = s->next; + } } if(s != nil) { - cursym = nil; + ctxt->cursym = nil; diag("unexpected symbol type %d for %s", s->type, s->name); } @@ -1274,8 +1001,8 @@ dodata(void) sect->align = maxalign(s, STYPELINK-1); datsize = rnd(datsize, sect->align); sect->vaddr = 0; - lookup("rodata", 0)->sect = sect; - lookup("erodata", 0)->sect = sect; + linklookup(ctxt, "rodata", 0)->sect = sect; + linklookup(ctxt, "erodata", 0)->sect = sect; for(; s != nil && s->type < STYPELINK; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; @@ -1290,8 +1017,8 @@ dodata(void) sect->align = maxalign(s, STYPELINK); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; - lookup("typelink", 0)->sect = sect; - lookup("etypelink", 0)->sect = sect; + linklookup(ctxt, "typelink", 0)->sect = sect; + linklookup(ctxt, "etypelink", 0)->sect = sect; for(; s != nil && s->type == STYPELINK; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; @@ -1306,8 +1033,8 @@ dodata(void) sect->align = maxalign(s, SPCLNTAB-1); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; - lookup("symtab", 0)->sect = sect; - lookup("esymtab", 0)->sect = sect; + linklookup(ctxt, "symtab", 0)->sect = sect; + linklookup(ctxt, "esymtab", 0)->sect = sect; for(; s != nil && s->type < SPCLNTAB; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; @@ -1322,8 +1049,8 @@ dodata(void) sect->align = maxalign(s, SELFROSECT-1); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; - lookup("pclntab", 0)->sect = sect; - lookup("epclntab", 0)->sect = sect; + linklookup(ctxt, "pclntab", 0)->sect = sect; + linklookup(ctxt, "epclntab", 0)->sect = sect; for(; s != nil && s->type < SELFROSECT; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; @@ -1366,9 +1093,8 @@ void textaddress(void) { uvlong va; - Prog *p; Section *sect; - Sym *sym, *sub; + LSym *sym, *sub; addsection(&segtext, ".text", 05); @@ -1376,28 +1102,24 @@ textaddress(void) // Could parallelize, by assigning to text // and then letting threads copy down, but probably not worth it. sect = segtext.sect; - sect->align = FuncAlign; - lookup("text", 0)->sect = sect; - lookup("etext", 0)->sect = sect; + sect->align = funcalign; + linklookup(ctxt, "text", 0)->sect = sect; + linklookup(ctxt, "etext", 0)->sect = sect; va = INITTEXT; sect->vaddr = va; - for(sym = textp; sym != nil; sym = sym->next) { + for(sym = ctxt->textp; sym != nil; sym = sym->next) { sym->sect = sect; if(sym->type & SSUB) continue; if(sym->align != 0) va = rnd(va, sym->align); - else if(sym->text != P) - va = rnd(va, FuncAlign); + else + va = rnd(va, funcalign); sym->value = 0; - for(sub = sym; sub != S; sub = sub->sub) { + 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; - } + if(sym->size == 0 && sym->sub != S) + ctxt->cursym = sym; va += sym->size; } sect->len = va - sect->vaddr; @@ -1409,7 +1131,7 @@ address(void) { Section *s, *text, *data, *rodata, *symtab, *pclntab, *noptr, *bss, *noptrbss; Section *typelink; - Sym *sym, *sub; + LSym *sym, *sub; uvlong va; vlong vlen; @@ -1418,13 +1140,14 @@ address(void) segtext.vaddr = va; segtext.fileoff = HEADR; for(s=segtext.sect; s != nil; s=s->next) { -//print("%s at %#llux + %#llux\n", s->name, va, (vlong)s->len); va = rnd(va, s->align); s->vaddr = va; va += s->len; } segtext.len = va - INITTEXT; segtext.filelen = segtext.len; + if(HEADTYPE == Hnacl) + va += 32; // room for the "halt sled" if(segrodata.sect != nil) { // align to page boundary so as not to mix @@ -1451,7 +1174,7 @@ address(void) segdata.filelen = 0; if(HEADTYPE == Hwindows) segdata.fileoff = segtext.fileoff + rnd(segtext.len, PEFILEALIGN); - if(HEADTYPE == Hplan9x64 || HEADTYPE == Hplan9x32) + if(HEADTYPE == Hplan9) segdata.fileoff = segtext.fileoff + segtext.filelen; data = nil; noptr = nil; @@ -1485,8 +1208,9 @@ address(void) pclntab = symtab->next; for(sym = datap; sym != nil; sym = sym->next) { - cursym = sym; - sym->value += sym->sect->vaddr; + ctxt->cursym = sym; + if(sym->sect != nil) + sym->value += sym->sect->vaddr; for(sub = sym->sub; sub != nil; sub = sub->sub) sub->value += sym->value; } @@ -1498,13 +1222,13 @@ address(void) xdefine("typelink", SRODATA, typelink->vaddr); xdefine("etypelink", SRODATA, typelink->vaddr + typelink->len); - sym = lookup("gcdata", 0); + sym = linklookup(ctxt, "gcdata", 0); xdefine("egcdata", SRODATA, symaddr(sym) + sym->size); - lookup("egcdata", 0)->sect = sym->sect; + linklookup(ctxt, "egcdata", 0)->sect = sym->sect; - sym = lookup("gcbss", 0); + sym = linklookup(ctxt, "gcbss", 0); xdefine("egcbss", SRODATA, symaddr(sym) + sym->size); - lookup("egcbss", 0)->sect = sym->sect; + linklookup(ctxt, "egcbss", 0)->sect = sym->sect; xdefine("symtab", SRODATA, symtab->vaddr); xdefine("esymtab", SRODATA, symtab->vaddr + symtab->len); diff --git a/src/cmd/ld/decodesym.c b/src/cmd/ld/decodesym.c index ab3f4fbd5..da48d3786 100644 --- a/src/cmd/ld/decodesym.c +++ b/src/cmd/ld/decodesym.c @@ -11,7 +11,7 @@ // ../gc/reflect.c stuffs in these. static Reloc* -decode_reloc(Sym *s, int32 off) +decode_reloc(LSym *s, int32 off) { int i; @@ -21,8 +21,8 @@ decode_reloc(Sym *s, int32 off) return nil; } -static Sym* -decode_reloc_sym(Sym *s, int32 off) +static LSym* +decode_reloc_sym(LSym *s, int32 off) { Reloc *r; @@ -67,103 +67,109 @@ decode_inuxi(uchar* p, int sz) return l; } +static int +commonsize(void) +{ + return 7*PtrSize + 8; +} + // Type.commonType.kind uint8 -decodetype_kind(Sym *s) +decodetype_kind(LSym *s) { return s->p[1*PtrSize + 7] & ~KindNoPointers; // 0x13 / 0x1f } // Type.commonType.size vlong -decodetype_size(Sym *s) +decodetype_size(LSym *s) { return decode_inuxi(s->p, PtrSize); // 0x8 / 0x10 } // Type.commonType.gc -Sym* -decodetype_gc(Sym *s) +LSym* +decodetype_gc(LSym *s) { return decode_reloc_sym(s, 1*PtrSize + 8 + 1*PtrSize); } // Type.ArrayType.elem and Type.SliceType.Elem -Sym* -decodetype_arrayelem(Sym *s) +LSym* +decodetype_arrayelem(LSym *s) { - return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30 + return decode_reloc_sym(s, commonsize()); // 0x1c / 0x30 } vlong -decodetype_arraylen(Sym *s) +decodetype_arraylen(LSym *s) { - return decode_inuxi(s->p + CommonSize+PtrSize, PtrSize); + return decode_inuxi(s->p + commonsize()+PtrSize, PtrSize); } // Type.PtrType.elem -Sym* -decodetype_ptrelem(Sym *s) +LSym* +decodetype_ptrelem(LSym *s) { - return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30 + return decode_reloc_sym(s, commonsize()); // 0x1c / 0x30 } // Type.MapType.key, elem -Sym* -decodetype_mapkey(Sym *s) +LSym* +decodetype_mapkey(LSym *s) { - return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30 + return decode_reloc_sym(s, commonsize()); // 0x1c / 0x30 } -Sym* -decodetype_mapvalue(Sym *s) +LSym* +decodetype_mapvalue(LSym *s) { - return decode_reloc_sym(s, CommonSize+PtrSize); // 0x20 / 0x38 + return decode_reloc_sym(s, commonsize()+PtrSize); // 0x20 / 0x38 } // Type.ChanType.elem -Sym* -decodetype_chanelem(Sym *s) +LSym* +decodetype_chanelem(LSym *s) { - return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30 + return decode_reloc_sym(s, commonsize()); // 0x1c / 0x30 } // Type.FuncType.dotdotdot int -decodetype_funcdotdotdot(Sym *s) +decodetype_funcdotdotdot(LSym *s) { - return s->p[CommonSize]; + return s->p[commonsize()]; } // Type.FuncType.in.len int -decodetype_funcincount(Sym *s) +decodetype_funcincount(LSym *s) { - return decode_inuxi(s->p + CommonSize+2*PtrSize, IntSize); + return decode_inuxi(s->p + commonsize()+2*PtrSize, IntSize); } int -decodetype_funcoutcount(Sym *s) +decodetype_funcoutcount(LSym *s) { - return decode_inuxi(s->p + CommonSize+3*PtrSize + 2*IntSize, IntSize); + return decode_inuxi(s->p + commonsize()+3*PtrSize + 2*IntSize, IntSize); } -Sym* -decodetype_funcintype(Sym *s, int i) +LSym* +decodetype_funcintype(LSym *s, int i) { Reloc *r; - r = decode_reloc(s, CommonSize + PtrSize); + r = decode_reloc(s, commonsize() + PtrSize); if (r == nil) return nil; return decode_reloc_sym(r->sym, r->add + i * PtrSize); } -Sym* -decodetype_funcouttype(Sym *s, int i) +LSym* +decodetype_funcouttype(LSym *s, int i) { Reloc *r; - r = decode_reloc(s, CommonSize + 2*PtrSize + 2*IntSize); + r = decode_reloc(s, commonsize() + 2*PtrSize + 2*IntSize); if (r == nil) return nil; return decode_reloc_sym(r->sym, r->add + i * PtrSize); @@ -171,22 +177,25 @@ decodetype_funcouttype(Sym *s, int i) // Type.StructType.fields.Slice::len int -decodetype_structfieldcount(Sym *s) +decodetype_structfieldcount(LSym *s) +{ + return decode_inuxi(s->p + commonsize() + PtrSize, IntSize); +} + +static int +structfieldsize(void) { - return decode_inuxi(s->p + CommonSize + PtrSize, IntSize); + return 5*PtrSize; } -enum { - StructFieldSize = 5*PtrSize -}; // Type.StructType.fields[]-> name, typ and offset. char* -decodetype_structfieldname(Sym *s, int i) +decodetype_structfieldname(LSym *s, int i) { Reloc *r; // go.string."foo" 0x28 / 0x40 - s = decode_reloc_sym(s, CommonSize + PtrSize + 2*IntSize + i*StructFieldSize); + s = decode_reloc_sym(s, commonsize() + PtrSize + 2*IntSize + i*structfieldsize()); if (s == nil) // embedded structs have a nil name. return nil; r = decode_reloc(s, 0); // s has a pointer to the string data at offset 0 @@ -195,21 +204,21 @@ decodetype_structfieldname(Sym *s, int i) return (char*) r->sym->p + r->add; // the c-string } -Sym* -decodetype_structfieldtype(Sym *s, int i) +LSym* +decodetype_structfieldtype(LSym *s, int i) { - return decode_reloc_sym(s, CommonSize + PtrSize + 2*IntSize + i*StructFieldSize + 2*PtrSize); + return decode_reloc_sym(s, commonsize() + PtrSize + 2*IntSize + i*structfieldsize() + 2*PtrSize); } vlong -decodetype_structfieldoffs(Sym *s, int i) +decodetype_structfieldoffs(LSym *s, int i) { - return decode_inuxi(s->p + CommonSize + PtrSize + 2*IntSize + i*StructFieldSize + 4*PtrSize, IntSize); + return decode_inuxi(s->p + commonsize() + PtrSize + 2*IntSize + i*structfieldsize() + 4*PtrSize, IntSize); } // InterfaceTYpe.methods.len vlong -decodetype_ifacemethodcount(Sym *s) +decodetype_ifacemethodcount(LSym *s) { - return decode_inuxi(s->p + CommonSize + PtrSize, IntSize); + return decode_inuxi(s->p + commonsize() + PtrSize, IntSize); } diff --git a/src/cmd/ld/doc.go b/src/cmd/ld/doc.go index 2adda25f2..8135bd549 100644 --- a/src/cmd/ld/doc.go +++ b/src/cmd/ld/doc.go @@ -43,6 +43,8 @@ Options new in this version: Write NetBSD ELF binaries (default when $GOOS is netbsd) -H openbsd (only in 6l/8l) Write OpenBSD ELF binaries (default when $GOOS is openbsd) + -H solaris (only in 6l) + Write Solaris ELF binaries (default when $GOOS is solaris) -H windows (only in 6l/8l) Write Windows PE32+ Console binaries (default when $GOOS is windows) -H windowsgui (only in 6l/8l) @@ -58,6 +60,8 @@ Options new in this version: Omit the symbol table and debug information. -V Print the linker version. + -w + Omit the DWARF symbol table. -X symbol value Set the value of an otherwise uninitialized string variable. The symbol name should be of the form importpath.name, diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c index c832bcc94..cc77b45cd 100644 --- a/src/cmd/ld/dwarf.c +++ b/src/cmd/ld/dwarf.c @@ -27,19 +27,19 @@ static vlong abbrevo; static vlong abbrevsize; -static Sym* abbrevsym; +static LSym* abbrevsym; static vlong abbrevsympos; static vlong lineo; static vlong linesize; -static Sym* linesym; +static LSym* linesym; static vlong linesympos; static vlong infoo; // also the base for DWDie->offs and reference attributes. static vlong infosize; -static Sym* infosym; +static LSym* infosym; static vlong infosympos; static vlong frameo; static vlong framesize; -static Sym* framesym; +static LSym* framesym; static vlong framesympos; static vlong pubnameso; static vlong pubnamessize; @@ -50,19 +50,19 @@ static vlong arangessize; static vlong gdbscripto; static vlong gdbscriptsize; -static Sym *infosec; +static LSym *infosec; static vlong inforeloco; static vlong inforelocsize; -static Sym *arangessec; +static LSym *arangessec; static vlong arangesreloco; static vlong arangesrelocsize; -static Sym *linesec; +static LSym *linesec; static vlong linereloco; static vlong linerelocsize; -static Sym *framesec; +static LSym *framesec; static vlong framereloco; static vlong framerelocsize; @@ -594,7 +594,7 @@ find_or_diag(DWDie *die, char* name) } static void -adddwarfrel(Sym* sec, Sym* sym, vlong offsetbase, int siz, vlong addend) +adddwarfrel(LSym* sec, LSym* sym, vlong offsetbase, int siz, vlong addend) { Reloc *r; @@ -603,7 +603,7 @@ adddwarfrel(Sym* sec, Sym* sym, vlong offsetbase, int siz, vlong addend) r->xsym = sym; r->off = cpos() - offsetbase; r->siz = siz; - r->type = D_ADDR; + r->type = R_ADDR; r->add = addend; r->xadd = addend; if(iself && thechar == '6') @@ -639,8 +639,8 @@ putattr(int abbrev, int form, int cls, vlong value, char *data) switch(form) { case DW_FORM_addr: // address if(linkmode == LinkExternal) { - value -= ((Sym*)data)->value; - adddwarfrel(infosec, (Sym*)data, infoo, PtrSize, value); + value -= ((LSym*)data)->value; + adddwarfrel(infosec, (LSym*)data, infoo, PtrSize, value); break; } addrput(value); @@ -651,8 +651,8 @@ putattr(int abbrev, int form, int cls, vlong value, char *data) cput(1+PtrSize); cput(DW_OP_addr); if(linkmode == LinkExternal) { - value -= ((Sym*)data)->value; - adddwarfrel(infosec, (Sym*)data, infoo, PtrSize, value); + value -= ((LSym*)data)->value; + adddwarfrel(infosec, (LSym*)data, infoo, PtrSize, value); break; } addrput(value); @@ -847,7 +847,7 @@ newmemberoffsetattr(DWDie *die, int32 offs) // 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, Sym *sym) +newabslocexprattr(DWDie *die, vlong addr, LSym *sym) { newattr(die, DW_AT_location, DW_CLS_ADDRESS, addr, (char*)sym); } @@ -864,12 +864,12 @@ enum { static DWDie* defptrto(DWDie *dwtype); // below // Lookup predefined types -static Sym* +static LSym* lookup_or_diag(char *n) { - Sym *s; + LSym *s; - s = rlookup(n, 0); + s = linkrlookup(ctxt, n, 0); if (s == nil || s->size == 0) { diag("dwarf: missing type: %s", n); errorexit(); @@ -904,10 +904,10 @@ dotypedef(DWDie *parent, char *name, DWDie *def) // Define gotype, for composite ones recurse into constituents. static DWDie* -defgotype(Sym *gotype) +defgotype(LSym *gotype) { DWDie *die, *fld; - Sym *s; + LSym *s; char *name, *f; uint8 kind; vlong bytesize; @@ -1099,21 +1099,29 @@ defptrto(DWDie *dwtype) } // Copies src's children into dst. Copies attributes by value. -// DWAttr.data is copied as pointer only. +// DWAttr.data is copied as pointer only. If except is one of +// the top-level children, it will not be copied. static void -copychildren(DWDie *dst, DWDie *src) +copychildrenexcept(DWDie *dst, DWDie *src, DWDie *except) { DWDie *c; DWAttr *a; for (src = src->child; src != nil; src = src->link) { + if(src == except) + continue; 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); + copychildrenexcept(c, src, nil); } reverselist(&dst->child); } +static void +copychildren(DWDie *dst, DWDie *src) +{ + copychildrenexcept(dst, src, nil); +} // Search children (assumed to have DW_TAG_member) for the one named // field and set its DW_AT_type to dwtype @@ -1253,7 +1261,10 @@ synthesizemaptypes(DWDie *die) mkinternaltypename("bucket", getattr(keytype, DW_AT_name)->data, getattr(valtype, DW_AT_name)->data)); - copychildren(dwhb, bucket); + // Copy over all fields except the field "data" from the generic bucket. + // "data" will be replaced with keys/values below. + copychildrenexcept(dwhb, bucket, find(bucket, "data")); + fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "keys"); newrefattr(fld, DW_AT_type, dwhk); newmemberoffsetattr(fld, BucketSize + PtrSize); @@ -1335,7 +1346,7 @@ synthesizechantypes(DWDie *die) // For use with pass.c::genasmsym static void -defdwsymb(Sym* sym, char *s, int t, vlong v, vlong size, int ver, Sym *gotype) +defdwsymb(LSym* sym, char *s, int t, vlong v, vlong size, int ver, LSym *gotype) { DWDie *dv, *dt; @@ -1371,284 +1382,37 @@ defdwsymb(Sym* sym, char *s, int t, vlong v, vlong size, int ver, Sym *gotype) 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 = dwroot.child->child; + while(die->link != nil) + die = die->link; 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 = erealloc(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("dwarf: corrupt z entry"); - return 0; - } - f = ftab[o]; - if (f == nil) { - diag("dwarf: corrupt z entry"); - return 0; - } - len += strlen(f) + 1; // for the '/' - ss += 2; - } - - if (len == 0) - return 0; - - r = malloc(len + 1); - if(r == nil) { - diag("out of memory"); - errorexit(); - } - 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 "", DW_LNS_set_file arguments must be > 0. -static int histfilesize; -static int histfilecap; - +// If the pcln table contains runtime/string.goc, use that to set gdbscript path. static void -clearhistfile(void) +finddebugruntimepath(LSym *s) { int i; + char *p; + LSym *f; + + if(gdbscript[0] != '\0') + return; - // [0] holds "" - 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 = erealloc(histfile, histfilecap * sizeof(char*)); - } - if (histfilesize == 0) - histfile[histfilesize++] = ""; - - fname = decodez(zentry); -// print("addhistfile %d: %s\n", histfilesize, fname); - 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(void) -{ - int i, l; - char *c; - - for (i = 1; i < histfilesize; i++) { - if ((c = strstr(histfile[i], "runtime/zruntime_defs")) != 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 a handful would be plenty, if it weren't for the fact that line -// directives can push an unlimited number of them. -static struct { - int file; - vlong line; -} *includestack; -static int includestacksize; -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) -{ - if (includetop < 0) { - diag("dwarf: corrupt z stack"); - errorexit(); - } - if (includetop >= includestacksize) { - includestacksize += 1; - includestacksize <<= 2; -// print("checknesting: growing to %d\n", includestacksize); - includestack = erealloc(includestack, includestacksize * sizeof *includestack); - } -} - -/* - * 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) + for(i=0; ipcln->nfile; i++) { + f = s->pcln->file[i]; + if((p = strstr(f->name, "runtime/string.goc")) != nil) { + *p = '\0'; + snprint(gdbscript, sizeof gdbscript, "%sruntime/runtime-gdb.py", f->name); + *p = 'r'; 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("dwarf: stray 'z' with offset %d", a->aoffset); - return 0; - } - - // Clear the history. - clearhistfile(); - includetop = 0; - checknesting(); - 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 { // pushed a file (potentially same) - 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 its 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); - if(lh == nil) { - diag("out of memory"); - errorexit(); - } - 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; } /* @@ -1659,7 +1423,7 @@ guesslang(char *s) enum { LINE_BASE = -1, LINE_RANGE = 4, - OPCODE_BASE = 5 + OPCODE_BASE = 10 }; static void @@ -1719,7 +1483,7 @@ mkvarname(char* name, int da) // flush previous compilation unit. static void -flushunit(DWDie *dwinfo, vlong pc, Sym *pcsym, vlong unitstart, int32 header_length) +flushunit(DWDie *dwinfo, vlong pc, LSym *pcsym, vlong unitstart, int32 header_length) { vlong here; @@ -1744,147 +1508,129 @@ flushunit(DWDie *dwinfo, vlong pc, Sym *pcsym, vlong unitstart, int32 header_len static void writelines(void) { - Prog *q; - Sym *s, *epcs; + LSym *s, *epcs; Auto *a; vlong unitstart, headerend, offs; - vlong pc, epc, lc, llc, lline; - int currfile; - int i, lang, da, dt; - Linehist *lh; + vlong pc, epc; + int i, lang, da, dt, line, file; DWDie *dwinfo, *dwfunc, *dwvar, **dws; DWDie *varhash[HASHSIZE]; char *n, *nn; + Pciter pcfile, pcline; + LSym **files, *f; if(linesec == S) - linesec = lookup(".dwarfline", 0); + linesec = linklookup(ctxt, ".dwarfline", 0); linesec->nr = 0; unitstart = -1; headerend = -1; - pc = 0; epc = 0; epcs = S; - lc = 1; - llc = 1; - currfile = -1; lineo = cpos(); dwinfo = nil; + + flushunit(dwinfo, epc, epcs, unitstart, headerend - unitstart - 10); + unitstart = cpos(); + + lang = DW_LANG_Go; + + s = ctxt->textp; + + dwinfo = newdie(&dwroot, DW_ABRV_COMPUNIT, estrdup("go")); + 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->value, (char*)s); + + // 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 by flushunit. + WPUT(2); // dwarf version (appendix F) + LPUT(0); // header_length (*), filled in by flushunit. + // cpos == unitstart + 4 + 2 + 4 + 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 + 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(1); // standard_opcode_lengths[5] + cput(0); // standard_opcode_lengths[6] + cput(0); // standard_opcode_lengths[7] + cput(0); // standard_opcode_lengths[8] + cput(1); // standard_opcode_lengths[9] + cput(0); // include_directories (empty) + + files = emallocz(ctxt->nhistfile*sizeof files[0]); + for(f = ctxt->filesyms; f != nil; f = f->next) + files[f->value-1] = f; + + for(i=0; inhistfile; i++) { + strnput(files[i]->name, strlen(files[i]->name) + 4); + // 4 zeros: the string termination + 3 fields. + } + + cput(0); // terminate file_names. + headerend = cpos(); + + cput(0); // start extended opcode + uleb128put(1 + PtrSize); + cput(DW_LNE_set_address); + + pc = s->value; + line = 1; + file = 1; + if(linkmode == LinkExternal) + adddwarfrel(linesec, s, lineo, PtrSize, 0); + else + addrput(pc); - 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, epcs, unitstart, headerend - unitstart - 10); - 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, estrdup(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, (char*)s); - - // 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 by flushunit. - WPUT(2); // dwarf version (appendix F) - LPUT(0); // header_length (*), filled in by flushunit. - // cpos == unitstart + 4 + 2 + 4 - 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) - - for (i=1; i < histfilesize; i++) { - strnput(histfile[i], strlen(histfile[i]) + 4); - // 4 zeros: the string termination + 3 fields. - } - - cput(0); // terminate file_names. - headerend = cpos(); - - pc = s->text->pc; - epc = pc; - epcs = s; - currfile = 1; - lc = 1; - llc = 1; - - cput(0); // start extended opcode - uleb128put(1 + PtrSize); - cput(DW_LNE_set_address); - - if(linkmode == LinkExternal) - adddwarfrel(linesec, s, lineo, PtrSize, 0); - else - addrput(pc); - } - if(s->text == nil) - continue; - - if (unitstart < 0) { - diag("dwarf: reachable code before seeing any history: %P", s->text); - continue; - } + for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next) { + s = ctxt->cursym; dwfunc = newdie(dwinfo, DW_ABRV_FUNCTION, s->name); newattr(dwfunc, DW_AT_low_pc, DW_CLS_ADDRESS, s->value, (char*)s); epc = s->value + s->size; + epcs = s; newattr(dwfunc, DW_AT_high_pc, DW_CLS_ADDRESS, epc, (char*)s); if (s->version == 0) newattr(dwfunc, DW_AT_external, DW_CLS_FLAG, 1, 0); - if(s->text->link == nil) + if(s->pcln == nil) continue; - for(q = s->text; q != P; q = q->link) { - lh = searchhist(q->line); - if (lh == nil) { - diag("dwarf: corrupt history or bad absolute line: %P", q); + finddebugruntimepath(s); + + pciterinit(ctxt, &pcfile, &s->pcln->pcfile); + pciterinit(ctxt, &pcline, &s->pcln->pcline); + epc = pc; + while(!pcfile.done && !pcline.done) { + if(epc - s->value >= pcfile.nextpc) { + pciternext(&pcfile); continue; } - - if (lh->file < 1) { // 0 is the past-EOF entry. - // diag("instruction with line number past EOF in %s: %P", histfile[1], q); + if(epc - s->value >= pcline.nextpc) { + pciternext(&pcline); 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; + if(file != pcfile.value) { cput(DW_LNS_set_file); - uleb128put(currfile); + uleb128put(pcfile.value); + file = pcfile.value; } - putpclcdelta(q->pc - pc, lline - llc); - pc = q->pc; - lc = q->line; - llc = lline; + putpclcdelta(s->value + pcline.pc - pc, pcline.value - line); + + pc = s->value + pcline.pc; + line = pcline.value; + if(pcfile.nextpc < pcline.nextpc) + epc = pcfile.nextpc; + else + epc = pcline.nextpc; + epc += s->value; } da = 0; @@ -1892,11 +1638,11 @@ writelines(void) memset(varhash, 0, sizeof varhash); for(a = s->autom; a; a = a->link) { switch (a->type) { - case D_AUTO: + case A_AUTO: dt = DW_ABRV_AUTO; offs = a->aoffset - PtrSize; break; - case D_PARAM: + case A_PARAM: dt = DW_ABRV_PARAM; offs = a->aoffset; break; @@ -1970,12 +1716,12 @@ putpccfadelta(vlong deltapc, vlong cfa) static void writeframes(void) { - Prog *p, *q; - Sym *s; - vlong fdeo, fdesize, pad, cfa, pc; + LSym *s; + vlong fdeo, fdesize, pad; + Pciter pcsp; if(framesec == S) - framesec = lookup(".dwarfframe", 0); + framesec = linklookup(ctxt, ".dwarfframe", 0); framesec->nr = 0; frameo = cpos(); @@ -2003,9 +1749,9 @@ writeframes(void) } strnput("", pad); - for(cursym = textp; cursym != nil; cursym = cursym->next) { - s = cursym; - if(s->text == nil) + for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next) { + s = ctxt->cursym; + if(s->pcln == nil) continue; fdeo = cpos(); @@ -2015,17 +1761,8 @@ writeframes(void) 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; - } + for(pciterinit(ctxt, &pcsp, &s->pcln->pcsp); !pcsp.done; pciternext(&pcsp)) + putpccfadelta(pcsp.nextpc - pcsp.pc, PtrSize + pcsp.value); fdesize = cpos() - fdeo - 4; // exclude the length field. pad = rnd(fdesize, PtrSize) - fdesize; @@ -2041,7 +1778,7 @@ writeframes(void) } else { LPUT(0); - addrput(p->pc); + addrput(s->value); } addrput(s->size); cseek(fdeo + 4 + fdesize); @@ -2067,11 +1804,11 @@ writeinfo(void) fwdcount = 0; if (infosec == S) - infosec = lookup(".dwarfinfo", 0); + infosec = linklookup(ctxt, ".dwarfinfo", 0); infosec->nr = 0; if(arangessec == S) - arangessec = lookup(".dwarfaranges", 0); + arangessec = linklookup(ctxt, ".dwarfaranges", 0); arangessec->nr = 0; for (compunit = dwroot.child; compunit; compunit = compunit->link) { @@ -2204,7 +1941,7 @@ writearanges(void) strnput("", headersize - (4+2+4+1+1)); // align to PtrSize if(linkmode == LinkExternal) - adddwarfrel(arangessec, (Sym*)b->data, sectionstart, PtrSize, b->value-((Sym*)b->data)->value); + adddwarfrel(arangessec, (LSym*)b->data, sectionstart, PtrSize, b->value-((LSym*)b->data)->value); else addrput(b->value); @@ -2239,7 +1976,7 @@ align(vlong size) } static vlong -writedwarfreloc(Sym* s) +writedwarfreloc(LSym* s) { int i; vlong start; @@ -2408,7 +2145,7 @@ enum vlong elfstrdbg[NElfStrDbg]; void -dwarfaddshstrings(Sym *shstrtab) +dwarfaddshstrings(LSym *shstrtab) { if(debug['w']) // disable dwarf return; @@ -2438,16 +2175,16 @@ dwarfaddshstrings(Sym *shstrtab) elfstrdbg[ElfStrRelDebugFrame] = addstring(shstrtab, ".rel.debug_frame"); } - infosym = lookup(".debug_info", 0); + infosym = linklookup(ctxt, ".debug_info", 0); infosym->hide = 1; - abbrevsym = lookup(".debug_abbrev", 0); + abbrevsym = linklookup(ctxt, ".debug_abbrev", 0); abbrevsym->hide = 1; - linesym = lookup(".debug_line", 0); + linesym = linklookup(ctxt, ".debug_line", 0); linesym->hide = 1; - framesym = lookup(".debug_frame", 0); + framesym = linklookup(ctxt, ".debug_frame", 0); framesym->hide = 1; } } @@ -2616,31 +2353,37 @@ dwarfaddmachoheaders(void) ms = newMachoSeg("__DWARF", nsect); ms->fileoffset = fakestart; ms->filesize = abbrevo-fakestart; + ms->vaddr = ms->fileoffset + segdata.vaddr - segdata.fileoff; msect = newMachoSect(ms, "__debug_abbrev", "__DWARF"); msect->off = abbrevo; msect->size = abbrevsize; + msect->addr = msect->off + segdata.vaddr - segdata.fileoff; ms->filesize += msect->size; msect = newMachoSect(ms, "__debug_line", "__DWARF"); msect->off = lineo; msect->size = linesize; + msect->addr = msect->off + segdata.vaddr - segdata.fileoff; ms->filesize += msect->size; msect = newMachoSect(ms, "__debug_frame", "__DWARF"); msect->off = frameo; msect->size = framesize; + msect->addr = msect->off + segdata.vaddr - segdata.fileoff; ms->filesize += msect->size; msect = newMachoSect(ms, "__debug_info", "__DWARF"); msect->off = infoo; msect->size = infosize; + msect->addr = msect->off + segdata.vaddr - segdata.fileoff; ms->filesize += msect->size; if (pubnamessize > 0) { msect = newMachoSect(ms, "__debug_pubnames", "__DWARF"); msect->off = pubnameso; msect->size = pubnamessize; + msect->addr = msect->off + segdata.vaddr - segdata.fileoff; ms->filesize += msect->size; } @@ -2648,6 +2391,7 @@ dwarfaddmachoheaders(void) msect = newMachoSect(ms, "__debug_pubtypes", "__DWARF"); msect->off = pubtypeso; msect->size = pubtypessize; + msect->addr = msect->off + segdata.vaddr - segdata.fileoff; ms->filesize += msect->size; } @@ -2655,6 +2399,7 @@ dwarfaddmachoheaders(void) msect = newMachoSect(ms, "__debug_aranges", "__DWARF"); msect->off = arangeso; msect->size = arangessize; + msect->addr = msect->off + segdata.vaddr - segdata.fileoff; ms->filesize += msect->size; } @@ -2663,6 +2408,7 @@ dwarfaddmachoheaders(void) msect = newMachoSect(ms, "__debug_gdb_scripts", "__DWARF"); msect->off = gdbscripto; msect->size = gdbscriptsize; + msect->addr = msect->off + segdata.vaddr - segdata.fileoff; ms->filesize += msect->size; } } diff --git a/src/cmd/ld/dwarf.h b/src/cmd/ld/dwarf.h index f0df2f9b1..32db36dcd 100644 --- a/src/cmd/ld/dwarf.h +++ b/src/cmd/ld/dwarf.h @@ -2,12 +2,6 @@ // 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. @@ -19,7 +13,7 @@ void dwarfemitdebugsections(void); * s[ection]h[eader]str[ing]tab. Prerequisite for * dwarfaddelfheaders(). */ -void dwarfaddshstrings(Sym *shstrtab); +void dwarfaddshstrings(LSym *shstrtab); /* * Add section headers pointing to the sections emitted in diff --git a/src/cmd/ld/elf.c b/src/cmd/ld/elf.c index 6b3638ec5..0555cf46a 100644 --- a/src/cmd/ld/elf.c +++ b/src/cmd/ld/elf.c @@ -55,8 +55,8 @@ elfinit(void) // 32-bit architectures case '5': - // we only use EABI on linux/arm - if(HEADTYPE == Hlinux) + // we use EABI on both linux/arm and freebsd/arm. + if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd) hdr.flags = 0x5000002; // has entry point, Version5 EABI // fallthrough default: @@ -287,35 +287,35 @@ elfhash(uchar *name) } void -elfwritedynent(Sym *s, int tag, uint64 val) +elfwritedynent(LSym *s, int tag, uint64 val) { if(elf64) { - adduint64(s, tag); - adduint64(s, val); + adduint64(ctxt, s, tag); + adduint64(ctxt, s, val); } else { - adduint32(s, tag); - adduint32(s, val); + adduint32(ctxt, s, tag); + adduint32(ctxt, s, val); } } void -elfwritedynentsym(Sym *s, int tag, Sym *t) +elfwritedynentsym(LSym *s, int tag, LSym *t) { if(elf64) - adduint64(s, tag); + adduint64(ctxt, s, tag); else - adduint32(s, tag); - addaddr(s, t); + adduint32(ctxt, s, tag); + addaddr(ctxt, s, t); } void -elfwritedynentsymsize(Sym *s, int tag, Sym *t) +elfwritedynentsymsize(LSym *s, int tag, LSym *t) { if(elf64) - adduint64(s, tag); + adduint64(ctxt, s, tag); else - adduint32(s, tag); - addsize(s, t); + adduint32(ctxt, s, tag); + addsize(ctxt, s, t); } int @@ -355,7 +355,7 @@ elfnote(ElfShdr *sh, uint64 startva, uint64 resoff, int sz) sh->addralign = 4; sh->addr = startva + resoff - n; sh->off = resoff - n; - sh->size = n; + sh->size = n - resoff % 4; return n; } @@ -388,7 +388,7 @@ elfnetbsdsig(ElfShdr *sh, uint64 startva, uint64 resoff) { int n; - n = ELF_NOTE_NETBSD_NAMESZ + ELF_NOTE_NETBSD_DESCSZ + 1; + n = rnd(ELF_NOTE_NETBSD_NAMESZ, 4) + rnd(ELF_NOTE_NETBSD_DESCSZ, 4); return elfnote(sh, startva, resoff, n); } @@ -561,7 +561,7 @@ haveaux: void elfdynhash(void) { - Sym *s, *sy, *dynstr; + LSym *s, *sy, *dynstr; int i, j, nbucket, b, nfile; uint32 hc, *chain, *buckets; int nsym; @@ -575,7 +575,7 @@ elfdynhash(void) return; nsym = nelfsym; - s = lookup(".hash", 0); + s = linklookup(ctxt, ".hash", 0); s->type = SELFROSECT; s->reachable = 1; @@ -591,14 +591,14 @@ elfdynhash(void) chain = malloc(nsym * sizeof chain[0]); buckets = malloc(nbucket * sizeof buckets[0]); if(need == nil || chain == nil || buckets == nil) { - cursym = nil; + ctxt->cursym = nil; diag("out of memory"); errorexit(); } memset(need, 0, nsym * sizeof need[0]); memset(chain, 0, nsym * sizeof chain[0]); memset(buckets, 0, nbucket * sizeof buckets[0]); - for(sy=allsym; sy!=S; sy=sy->allsym) { + for(sy=ctxt->allsym; sy!=S; sy=sy->allsym) { if (sy->dynid <= 0) continue; @@ -613,70 +613,87 @@ elfdynhash(void) buckets[b] = sy->dynid; } - adduint32(s, nbucket); - adduint32(s, nsym); + adduint32(ctxt, s, nbucket); + adduint32(ctxt, s, nsym); for(i = 0; inext) { nfile++; // header - adduint16(s, 1); // table version + adduint16(ctxt, s, 1); // table version j = 0; for(x=l->aux; x; x=x->next) j++; - adduint16(s, j); // aux count - adduint32(s, addstring(dynstr, l->file)); // file string offset - adduint32(s, 16); // offset from header to first aux + adduint16(ctxt, s, j); // aux count + adduint32(ctxt, s, addstring(dynstr, l->file)); // file string offset + adduint32(ctxt, s, 16); // offset from header to first aux if(l->next) - adduint32(s, 16+j*16); // offset from this header to next + adduint32(ctxt, s, 16+j*16); // offset from this header to next else - adduint32(s, 0); + adduint32(ctxt, s, 0); for(x=l->aux; x; x=x->next) { x->num = i++; // aux struct - adduint32(s, elfhash((uchar*)x->vers)); // hash - adduint16(s, 0); // flags - adduint16(s, x->num); // other - index we refer to this by - adduint32(s, addstring(dynstr, x->vers)); // version string offset + adduint32(ctxt, s, elfhash((uchar*)x->vers)); // hash + adduint16(ctxt, s, 0); // flags + adduint16(ctxt, s, x->num); // other - index we refer to this by + adduint32(ctxt, s, addstring(dynstr, x->vers)); // version string offset if(x->next) - adduint32(s, 16); // offset from this aux to next + adduint32(ctxt, s, 16); // offset from this aux to next else - adduint32(s, 0); + adduint32(ctxt, s, 0); } } // version references - s = lookup(".gnu.version", 0); + s = linklookup(ctxt, ".gnu.version", 0); for(i=0; inum); + adduint16(ctxt, s, need[i]->num); } free(need); - s = lookup(".dynamic", 0); + s = linklookup(ctxt, ".dynamic", 0); elfverneed = nfile; if(elfverneed) { - elfwritedynentsym(s, DT_VERNEED, lookup(".gnu.version_r", 0)); + elfwritedynentsym(s, DT_VERNEED, linklookup(ctxt, ".gnu.version_r", 0)); elfwritedynent(s, DT_VERNEEDNUM, nfile); - elfwritedynentsym(s, DT_VERSYM, lookup(".gnu.version", 0)); + elfwritedynentsym(s, DT_VERSYM, linklookup(ctxt, ".gnu.version", 0)); + } + + if(thechar == '6') { + sy = linklookup(ctxt, ".rela.plt", 0); + if(sy->size > 0) { + elfwritedynent(s, DT_PLTREL, DT_RELA); + elfwritedynentsymsize(s, DT_PLTRELSZ, sy); + elfwritedynentsym(s, DT_JMPREL, sy); + } + } else { + sy = linklookup(ctxt, ".rel.plt", 0); + if(sy->size > 0) { + elfwritedynent(s, DT_PLTREL, DT_REL); + elfwritedynentsymsize(s, DT_PLTRELSZ, sy); + elfwritedynentsym(s, DT_JMPREL, sy); + } } + elfwritedynent(s, DT_NULL, 0); } @@ -797,19 +814,19 @@ elfshreloc(Section *sect) snprint(buf, sizeof buf, "%s%s", prefix, sect->name); sh = elfshname(buf); sh->type = typ; - sh->entsize = PtrSize*(2+(typ==SHT_RELA)); + sh->entsize = RegSize*(2+(typ==SHT_RELA)); sh->link = elfshname(".symtab")->shnum; sh->info = sect->elfsect->shnum; sh->off = sect->reloff; sh->size = sect->rellen; - sh->addralign = PtrSize; + sh->addralign = RegSize; return sh; } void -elfrelocsect(Section *sect, Sym *first) +elfrelocsect(Section *sect, LSym *first) { - Sym *sym; + LSym *sym; int32 eaddr; Reloc *r; @@ -834,7 +851,7 @@ elfrelocsect(Section *sect, Sym *first) continue; if(sym->value >= eaddr) break; - cursym = sym; + ctxt->cursym = sym; for(r = sym->r; r < sym->r+sym->nr; r++) { if(r->done) @@ -861,7 +878,7 @@ elfemitreloc(void) while(cpos()&7) cput(0); - elfrelocsect(segtext.sect, textp); + elfrelocsect(segtext.sect, ctxt->textp); for(sect=segtext.sect->next; sect!=nil; sect=sect->next) elfrelocsect(sect, datap); for(sect=segrodata.sect; sect!=nil; sect=sect->next) @@ -873,13 +890,13 @@ elfemitreloc(void) void doelf(void) { - Sym *s, *shstrtab, *dynstr; + LSym *s, *shstrtab, *dynstr; if(!iself) return; /* predefine strings we need for section headers */ - shstrtab = lookup(".shstrtab", 0); + shstrtab = linklookup(ctxt, ".shstrtab", 0); shstrtab->type = SELFROSECT; shstrtab->reachable = 1; @@ -969,7 +986,7 @@ doelf(void) addstring(shstrtab, ".gnu.version_r"); /* dynamic symbol table - first entry all zeros */ - s = lookup(".dynsym", 0); + s = linklookup(ctxt, ".dynsym", 0); s->type = SELFROSECT; s->reachable = 1; if(thechar == '6') @@ -978,7 +995,7 @@ doelf(void) s->size += ELF32SYMSIZE; /* dynamic string table */ - s = lookup(".dynstr", 0); + s = linklookup(ctxt, ".dynstr", 0); s->type = SELFROSECT; s->reachable = 1; if(s->size == 0) @@ -987,87 +1004,81 @@ doelf(void) /* relocation table */ if(thechar == '6') - s = lookup(".rela", 0); + s = linklookup(ctxt, ".rela", 0); else - s = lookup(".rel", 0); + s = linklookup(ctxt, ".rel", 0); s->reachable = 1; s->type = SELFROSECT; /* global offset table */ - s = lookup(".got", 0); + s = linklookup(ctxt, ".got", 0); s->reachable = 1; s->type = SELFSECT; // writable /* hash */ - s = lookup(".hash", 0); + s = linklookup(ctxt, ".hash", 0); s->reachable = 1; s->type = SELFROSECT; - s = lookup(".got.plt", 0); + s = linklookup(ctxt, ".got.plt", 0); s->reachable = 1; s->type = SELFSECT; // writable - s = lookup(".plt", 0); + s = linklookup(ctxt, ".plt", 0); s->reachable = 1; s->type = SELFRXSECT; elfsetupplt(); if(thechar == '6') - s = lookup(".rela.plt", 0); + s = linklookup(ctxt, ".rela.plt", 0); else - s = lookup(".rel.plt", 0); + s = linklookup(ctxt, ".rel.plt", 0); s->reachable = 1; s->type = SELFROSECT; - s = lookup(".gnu.version", 0); + s = linklookup(ctxt, ".gnu.version", 0); s->reachable = 1; s->type = SELFROSECT; - s = lookup(".gnu.version_r", 0); + s = linklookup(ctxt, ".gnu.version_r", 0); s->reachable = 1; s->type = SELFROSECT; /* define dynamic elf table */ - s = lookup(".dynamic", 0); + s = linklookup(ctxt, ".dynamic", 0); s->reachable = 1; s->type = SELFSECT; // writable /* * .dynamic table */ - elfwritedynentsym(s, DT_HASH, lookup(".hash", 0)); - elfwritedynentsym(s, DT_SYMTAB, lookup(".dynsym", 0)); + elfwritedynentsym(s, DT_HASH, linklookup(ctxt, ".hash", 0)); + elfwritedynentsym(s, DT_SYMTAB, linklookup(ctxt, ".dynsym", 0)); if(thechar == '6') elfwritedynent(s, DT_SYMENT, ELF64SYMSIZE); else elfwritedynent(s, DT_SYMENT, ELF32SYMSIZE); - elfwritedynentsym(s, DT_STRTAB, lookup(".dynstr", 0)); - elfwritedynentsymsize(s, DT_STRSZ, lookup(".dynstr", 0)); + elfwritedynentsym(s, DT_STRTAB, linklookup(ctxt, ".dynstr", 0)); + elfwritedynentsymsize(s, DT_STRSZ, linklookup(ctxt, ".dynstr", 0)); if(thechar == '6') { - elfwritedynentsym(s, DT_RELA, lookup(".rela", 0)); - elfwritedynentsymsize(s, DT_RELASZ, lookup(".rela", 0)); + elfwritedynentsym(s, DT_RELA, linklookup(ctxt, ".rela", 0)); + elfwritedynentsymsize(s, DT_RELASZ, linklookup(ctxt, ".rela", 0)); elfwritedynent(s, DT_RELAENT, ELF64RELASIZE); } else { - elfwritedynentsym(s, DT_REL, lookup(".rel", 0)); - elfwritedynentsymsize(s, DT_RELSZ, lookup(".rel", 0)); + elfwritedynentsym(s, DT_REL, linklookup(ctxt, ".rel", 0)); + elfwritedynentsymsize(s, DT_RELSZ, linklookup(ctxt, ".rel", 0)); elfwritedynent(s, DT_RELENT, ELF32RELSIZE); } if(rpath) elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath)); - elfwritedynentsym(s, DT_PLTGOT, lookup(".got.plt", 0)); + elfwritedynentsym(s, DT_PLTGOT, linklookup(ctxt, ".got.plt", 0)); - if(thechar == '6') { - elfwritedynent(s, DT_PLTREL, DT_RELA); - elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rela.plt", 0)); - elfwritedynentsym(s, DT_JMPREL, lookup(".rela.plt", 0)); - } else { - elfwritedynent(s, DT_PLTREL, DT_REL); - elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rel.plt", 0)); - elfwritedynentsym(s, DT_JMPREL, lookup(".rel.plt", 0)); - } - + // Solaris dynamic linker can't handle an empty .rela.plt if + // DT_JMPREL is emitted so we have to defer generation of DT_PLTREL, + // DT_PLTRELSZ, and DT_JMPREL dynamic entries until after we know the + // size of .rel(a).plt section. elfwritedynent(s, DT_DEBUG, 0); // Do not write DT_NULL. elfdynhash will finish it. @@ -1075,7 +1086,7 @@ doelf(void) } void -shsym(ElfShdr *sh, Sym *s) +shsym(ElfShdr *sh, LSym *s) { vlong addr; addr = symaddr(s); @@ -1152,7 +1163,7 @@ asmbelf(vlong symo) /* program header info */ pph = newElfPhdr(); pph->type = PT_PHDR; - pph->flags = PF_R + PF_X; + pph->flags = PF_R; pph->off = eh->ehsize; pph->vaddr = INITTEXT - HEADR + pph->off; pph->paddr = INITTEXT - HEADR + pph->off; @@ -1161,13 +1172,16 @@ asmbelf(vlong symo) /* * PHDR must be in a loaded segment. Adjust the text * segment boundaries downwards to include it. + * Except on NaCl where it must not be loaded. */ - o = segtext.vaddr - pph->vaddr; - segtext.vaddr -= o; - segtext.len += o; - o = segtext.fileoff - pph->off; - segtext.fileoff -= o; - segtext.filelen += o; + if(HEADTYPE != Hnacl) { + o = segtext.vaddr - pph->vaddr; + segtext.vaddr -= o; + segtext.len += o; + o = segtext.fileoff - pph->off; + segtext.fileoff -= o; + segtext.filelen += o; + } if(!debug['d']) { /* interpreter */ @@ -1192,6 +1206,9 @@ asmbelf(vlong symo) case Hdragonfly: interpreter = dragonflydynld; break; + case Hsolaris: + interpreter = solarisdynld; + break; } } resoff -= elfinterp(sh, startva, resoff, interpreter); @@ -1247,20 +1264,20 @@ asmbelf(vlong symo) sh = elfshname(".dynsym"); sh->type = SHT_DYNSYM; sh->flags = SHF_ALLOC; - if(PtrSize == 8) + if(elf64) sh->entsize = ELF64SYMSIZE; else sh->entsize = ELF32SYMSIZE; - sh->addralign = PtrSize; + sh->addralign = RegSize; sh->link = elfshname(".dynstr")->shnum; // sh->info = index of first non-local symbol (number of local symbols) - shsym(sh, lookup(".dynsym", 0)); + shsym(sh, linklookup(ctxt, ".dynsym", 0)); sh = elfshname(".dynstr"); sh->type = SHT_STRTAB; sh->flags = SHF_ALLOC; sh->addralign = 1; - shsym(sh, lookup(".dynstr", 0)); + shsym(sh, linklookup(ctxt, ".dynstr", 0)); if(elfverneed) { sh = elfshname(".gnu.version"); @@ -1269,15 +1286,15 @@ asmbelf(vlong symo) sh->addralign = 2; sh->link = elfshname(".dynsym")->shnum; sh->entsize = 2; - shsym(sh, lookup(".gnu.version", 0)); + shsym(sh, linklookup(ctxt, ".gnu.version", 0)); sh = elfshname(".gnu.version_r"); sh->type = SHT_GNU_VERNEED; sh->flags = SHF_ALLOC; - sh->addralign = PtrSize; + sh->addralign = RegSize; sh->info = elfverneed; sh->link = elfshname(".dynstr")->shnum; - shsym(sh, lookup(".gnu.version_r", 0)); + shsym(sh, linklookup(ctxt, ".gnu.version_r", 0)); } switch(eh->machine) { @@ -1286,10 +1303,10 @@ asmbelf(vlong symo) sh->type = SHT_RELA; sh->flags = SHF_ALLOC; sh->entsize = ELF64RELASIZE; - sh->addralign = PtrSize; + sh->addralign = RegSize; sh->link = elfshname(".dynsym")->shnum; sh->info = elfshname(".plt")->shnum; - shsym(sh, lookup(".rela.plt", 0)); + shsym(sh, linklookup(ctxt, ".rela.plt", 0)); sh = elfshname(".rela"); sh->type = SHT_RELA; @@ -1297,7 +1314,7 @@ asmbelf(vlong symo) sh->entsize = ELF64RELASIZE; sh->addralign = 8; sh->link = elfshname(".dynsym")->shnum; - shsym(sh, lookup(".rela", 0)); + shsym(sh, linklookup(ctxt, ".rela", 0)); break; default: @@ -1306,7 +1323,7 @@ asmbelf(vlong symo) sh->flags = SHF_ALLOC; sh->entsize = ELF32RELSIZE; sh->link = elfshname(".dynsym")->shnum; - shsym(sh, lookup(".rel.plt", 0)); + shsym(sh, linklookup(ctxt, ".rel.plt", 0)); sh = elfshname(".rel"); sh->type = SHT_REL; @@ -1314,7 +1331,7 @@ asmbelf(vlong symo) sh->entsize = ELF32RELSIZE; sh->addralign = 4; sh->link = elfshname(".dynsym")->shnum; - shsym(sh, lookup(".rel", 0)); + shsym(sh, linklookup(ctxt, ".rel", 0)); break; } @@ -1326,38 +1343,38 @@ asmbelf(vlong symo) else sh->entsize = 4; sh->addralign = 4; - shsym(sh, lookup(".plt", 0)); + shsym(sh, linklookup(ctxt, ".plt", 0)); sh = elfshname(".got"); sh->type = SHT_PROGBITS; sh->flags = SHF_ALLOC+SHF_WRITE; - sh->entsize = PtrSize; - sh->addralign = PtrSize; - shsym(sh, lookup(".got", 0)); + sh->entsize = RegSize; + sh->addralign = RegSize; + shsym(sh, linklookup(ctxt, ".got", 0)); sh = elfshname(".got.plt"); sh->type = SHT_PROGBITS; sh->flags = SHF_ALLOC+SHF_WRITE; - sh->entsize = PtrSize; - sh->addralign = PtrSize; - shsym(sh, lookup(".got.plt", 0)); + sh->entsize = RegSize; + sh->addralign = RegSize; + shsym(sh, linklookup(ctxt, ".got.plt", 0)); sh = elfshname(".hash"); sh->type = SHT_HASH; sh->flags = SHF_ALLOC; sh->entsize = 4; - sh->addralign = PtrSize; + sh->addralign = RegSize; sh->link = elfshname(".dynsym")->shnum; - shsym(sh, lookup(".hash", 0)); + shsym(sh, linklookup(ctxt, ".hash", 0)); /* sh and PT_DYNAMIC for .dynamic section */ sh = elfshname(".dynamic"); sh->type = SHT_DYNAMIC; sh->flags = SHF_ALLOC+SHF_WRITE; - sh->entsize = 2*PtrSize; - sh->addralign = PtrSize; + sh->entsize = 2*RegSize; + sh->addralign = RegSize; sh->link = elfshname(".dynstr")->shnum; - shsym(sh, lookup(".dynamic", 0)); + shsym(sh, linklookup(ctxt, ".dynamic", 0)); ph = newElfPhdr(); ph->type = PT_DYNAMIC; ph->flags = PF_R + PF_W; @@ -1369,12 +1386,12 @@ asmbelf(vlong symo) // Do not emit PT_TLS for OpenBSD since ld.so(1) does // not currently support it. This is handled // appropriately in runtime/cgo. - if(tlsoffset != 0 && HEADTYPE != Hopenbsd) { + if(ctxt->tlsoffset != 0 && HEADTYPE != Hopenbsd) { ph = newElfPhdr(); ph->type = PT_TLS; ph->flags = PF_R; - ph->memsz = -tlsoffset; - ph->align = PtrSize; + ph->memsz = -ctxt->tlsoffset; + ph->align = RegSize; } } @@ -1382,19 +1399,19 @@ asmbelf(vlong symo) ph = newElfPhdr(); ph->type = PT_GNU_STACK; ph->flags = PF_W+PF_R; - ph->align = PtrSize; + ph->align = RegSize; ph = newElfPhdr(); ph->type = PT_PAX_FLAGS; ph->flags = 0x2a00; // mprotect, randexec, emutramp disabled - ph->align = PtrSize; + ph->align = RegSize; } elfobj: sh = elfshname(".shstrtab"); sh->type = SHT_STRTAB; sh->addralign = 1; - shsym(sh, lookup(".shstrtab", 0)); + shsym(sh, linklookup(ctxt, ".shstrtab", 0)); eh->shstrndx = sh->shnum; // put these sections early in the list @@ -1429,8 +1446,8 @@ elfobj: if(linkmode == LinkInternal && !debug['d'] && HEADTYPE != Hopenbsd) { sh = elfshname(".tbss"); sh->type = SHT_NOBITS; - sh->addralign = PtrSize; - sh->size = -tlsoffset; + sh->addralign = RegSize; + sh->size = -ctxt->tlsoffset; sh->flags = SHF_ALLOC | SHF_TLS | SHF_WRITE; } @@ -1439,8 +1456,8 @@ elfobj: sh->type = SHT_SYMTAB; sh->off = symo; sh->size = symsize; - sh->addralign = PtrSize; - sh->entsize = 8+2*PtrSize; + sh->addralign = RegSize; + sh->entsize = 8+2*RegSize; sh->link = elfshname(".strtab")->shnum; sh->info = elfglobalsymndx; @@ -1466,7 +1483,7 @@ elfobj: eh->ident[EI_OSABI] = ELFOSABI_OPENBSD; else if(HEADTYPE == Hdragonfly) eh->ident[EI_OSABI] = ELFOSABI_NONE; - if(PtrSize == 8) + if(elf64) eh->ident[EI_CLASS] = ELFCLASS64; else eh->ident[EI_CLASS] = ELFCLASS32; @@ -1504,5 +1521,5 @@ elfobj: a += elfwritebuildinfo(); } if(a > ELFRESERVE) - diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE); + diag("ELFRESERVE too small: %lld > %d", a, ELFRESERVE); } diff --git a/src/cmd/ld/elf.h b/src/cmd/ld/elf.h index 5b2ff041a..e84d996f2 100644 --- a/src/cmd/ld/elf.h +++ b/src/cmd/ld/elf.h @@ -858,7 +858,7 @@ struct Elf64_Shdr { Elf64_Xword entsize; /* Size of each entry in section. */ int shnum; /* section number, not stored on disk */ - Sym* secsym; /* section symbol, if needed; not on disk */ + LSym* secsym; /* section symbol, if needed; not on disk */ }; /* @@ -968,9 +968,9 @@ ElfPhdr *newElfPhdr(void); uint32 elfwritehdr(void); uint32 elfwritephdrs(void); uint32 elfwriteshdrs(void); -void elfwritedynent(Sym*, int, uint64); -void elfwritedynentsym(Sym*, int, Sym*); -void elfwritedynentsymsize(Sym*, int, Sym*); +void elfwritedynent(LSym*, int, uint64); +void elfwritedynentsym(LSym*, int, LSym*); +void elfwritedynentsymsize(LSym*, int, LSym*); uint32 elfhash(uchar*); uint64 startelf(void); uint64 endelf(void); @@ -994,13 +994,13 @@ ElfShdr* elfshalloc(Section*); ElfShdr* elfshname(char*); ElfShdr* elfshreloc(Section*); void elfsetstring(char*, int); -void elfaddverneed(Sym*); +void elfaddverneed(LSym*); void elfemitreloc(void); -void shsym(ElfShdr*, Sym*); +void shsym(ElfShdr*, LSym*); void phsh(ElfPhdr*, ElfShdr*); void doelf(void); void elfsetupplt(void); -void dwarfaddshstrings(Sym*); +void dwarfaddshstrings(LSym*); void dwarfaddelfsectionsyms(void); void dwarfaddelfheaders(void); void asmbelf(vlong symo); @@ -1010,6 +1010,7 @@ extern char freebsddynld[]; extern char netbsddynld[]; extern char openbsddynld[]; extern char dragonflydynld[]; +extern char solarisdynld[]; int elfreloc1(Reloc*, vlong sectoff); void putelfsectionsyms(void); diff --git a/src/cmd/ld/go.c b/src/cmd/ld/go.c index 39ffa3d87..9c296b740 100644 --- a/src/cmd/ld/go.c +++ b/src/cmd/ld/go.c @@ -151,28 +151,11 @@ ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence) } loadpkgdata(filename, pkg, p0, p1 - p0); } - - // The __.PKGDEF archive summary has no local types. + + // __.PKGDEF has no cgo section - those are in the C compiler-generated object files. if(whence == Pkgdef) return; - // local types begin where exports end. - // skip rest of line after $$ we found above - p0 = p1 + 3; - while(*p0 != '\n' && *p0 != '\0') - p0++; - - // local types end at next \n$$. - p1 = strstr(p0, "\n$$"); - if(p1 == nil) { - fprint(2, "%s: cannot find end of local types in %s\n", argv0, filename); - if(debug['u']) - errorexit(); - return; - } - - loadpkgdata(filename, pkg, p0, p1 - p0); - // look for cgo section p0 = strstr(p1, "\n$$ // cgo"); if(p0 != nil) { @@ -228,39 +211,6 @@ loadpkgdata(char *file, char *pkg, char *data, int len) free(file); } -// replace all "". with pkg. -char* -expandpkg(char *t0, char *pkg) -{ - int n; - char *p; - char *w, *w0, *t; - - n = 0; - for(p=t0; (p=strstr(p, "\"\".")) != nil; p+=3) - n++; - - if(n == 0) - return estrdup(t0); - - // 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); - w += p-t; - strcpy(w, pkg); - w += strlen(pkg); - t = p+2; - } - strcpy(w, t); - return w0; -} - static int parsepkgdata(char *file, char *pkg, char **pp, char *ep, char **prefixp, char **namep, char **defp) { @@ -413,7 +363,7 @@ loadcgo(char *file, char *pkg, char *p, int n) char *pend, *next, *p0, *q; char *f[10], *local, *remote, *lib; int nf; - Sym *s; + LSym *s; USED(file); pend = p + n; @@ -459,7 +409,7 @@ loadcgo(char *file, char *pkg, char *p, int n) q = strchr(remote, '#'); if(q) *q++ = '\0'; - s = lookup(local, 0); + s = linklookup(ctxt, local, 0); if(local != f[1]) free(local); if(s->type == 0 || s->type == SXREF || s->type == SHOSTOBJ) { @@ -477,7 +427,7 @@ loadcgo(char *file, char *pkg, char *p, int n) if(nf != 2) goto err; local = f[1]; - s = lookup(local, 0); + s = linklookup(ctxt, local, 0); s->type = SHOSTOBJ; s->size = 0; continue; @@ -496,9 +446,9 @@ loadcgo(char *file, char *pkg, char *p, int n) else remote = local; local = expandpkg(local, pkg); - s = lookup(local, 0); + s = linklookup(ctxt, local, 0); - if(flag_shared && s == lookup("main", 0)) + if(flag_shared && s == linklookup(ctxt, "main", 0)) continue; // export overrides import, for openbsd/cgo. @@ -562,11 +512,11 @@ err: nerrors++; } -static Sym *markq; -static Sym *emarkq; +static LSym *markq; +static LSym *emarkq; static void -mark1(Sym *s, Sym *parent) +mark1(LSym *s, LSym *parent) { if(s == S || s->reachable) return; @@ -582,7 +532,7 @@ mark1(Sym *s, Sym *parent) } void -mark(Sym *s) +mark(LSym *s) { mark1(s, nil); } @@ -591,23 +541,22 @@ static void markflood(void) { Auto *a; - Prog *p; - Sym *s; + LSym *s; int i; for(s=markq; s!=S; s=s->queue) { - if(s->text) { + if(s->type == STEXT) { if(debug['v'] > 1) Bprint(&bso, "marktext %s\n", s->name); for(a=s->autom; a; a=a->link) mark1(a->gotype, s); - for(p=s->text; p != P; p=p->link) { - mark1(p->from.sym, s); - mark1(p->to.sym, s); - } } for(i=0; inr; i++) mark1(s->r[i].sym, s); + if(s->pcln) { + for(i=0; ipcln->nfuncdata; i++) + mark1(s->pcln->funcdata[i], s); + } mark1(s->gotype, s); mark1(s->sub, s); mark1(s->outer, s); @@ -639,51 +588,19 @@ markextra[] = "_modu", }; -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, *p; - Auto *z; + LSym *s, *last, *p; Fmt fmt; if(debug['v']) Bprint(&bso, "%5.2f deadcode\n", cputime()); - mark(lookup(INITENTRY, 0)); + mark(linklookup(ctxt, INITENTRY, 0)); for(i=0; iallsym) { + for(s = ctxt->allsym; s != S; s = s->allsym) { if(strncmp(s->name, "go.typelink.", 12) == 0) s->reachable = s->nr==1 && s->r[0].sym->reachable; } // 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; + for(s = ctxt->textp; s != nil; s = s->next) { + if(!s->reachable) continue; - } + // NOTE: Removing s from old textp and adding to new, shorter textp. if(last == nil) - textp = s; + ctxt->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; + ctxt->textp = nil; else last->next = nil; - for(s = allsym; s != S; s = s->allsym) + for(s = ctxt->allsym; s != S; s = s->allsym) if(strncmp(s->name, "go.weak.", 8) == 0) { s->special = 1; // do not lay out in data segment s->reachable = 1; @@ -730,7 +639,7 @@ deadcode(void) // record field tracking references fmtstrinit(&fmt); - for(s = allsym; s != S; s = s->allsym) { + for(s = ctxt->allsym; s != S; s = s->allsym) { if(strncmp(s->name, "go.track.", 9) == 0) { s->special = 1; // do not lay out in data segment s->hide = 1; @@ -746,7 +655,7 @@ deadcode(void) } if(tracksym == nil) return; - s = lookup(tracksym, 0); + s = linklookup(ctxt, tracksym, 0); if(!s->reachable) return; addstrdata(tracksym, fmtstrflush(&fmt)); @@ -755,13 +664,13 @@ deadcode(void) void doweak(void) { - Sym *s, *t; + LSym *s, *t; // resolve weak references only if // target symbol will be in binary anyway. - for(s = allsym; s != S; s = s->allsym) { + for(s = ctxt->allsym; s != S; s = s->allsym) { if(strncmp(s->name, "go.weak.", 8) == 0) { - t = rlookup(s->name+8, s->version); + t = linkrlookup(ctxt, s->name+8, s->version); if(t && t->type != 0 && t->reachable) { s->value = t->value; s->type = t->type; @@ -784,7 +693,7 @@ addexport(void) return; for(i=0; ivalue < b->value) return -1; @@ -336,15 +336,15 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn) ElfSym sym; Endian *e; Reloc *r, *rp; - Sym *s; - Sym **symbols; + LSym *s; + LSym **symbols; symbols = nil; if(debug['v']) Bprint(&bso, "%5.2f ldelf %s\n", cputime(), pn); - version++; + ctxt->version++; base = Boffset(f); if(Bread(f, hdrbuf, sizeof hdrbuf) != sizeof hdrbuf) @@ -529,7 +529,7 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn) goto bad; name = smprint("%s(%s)", pkg, sect->name); - s = lookup(name, version); + s = linklookup(ctxt, name, ctxt->version); free(name); switch((int)sect->flags&(ElfSectFlagAlloc|ElfSectFlagWrite|ElfSectFlagExec)) { default: @@ -601,24 +601,9 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn) s->size = sym.size; s->outer = sect->sym; if(sect->sym->type == STEXT) { - Prog *p; - - if(s->text != P) { - if(!s->dupok) + if(s->external && !s->dupok) diag("%s: duplicate definition of %s", pn, s->name); - } else { - // 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; - } + s->external = 1; } } @@ -629,16 +614,22 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn) if(s == S) continue; if(s->sub) - s->sub = listsort(s->sub, valuecmp, offsetof(Sym, sub)); + s->sub = listsort(s->sub, valuecmp, offsetof(LSym, sub)); if(s->type == STEXT) { - if(etextp) - etextp->next = s; + if(s->onlist) + sysfatal("symbol %s listed multiple times", s->name); + s->onlist = 1; + if(ctxt->etextp) + ctxt->etextp->next = s; else - textp = s; - etextp = s; + ctxt->textp = s; + ctxt->etextp = s; for(s = s->sub; s != S; s = s->sub) { - etextp->next = s; - etextp = s; + if(s->onlist) + sysfatal("symbol %s listed multiple times", s->name); + s->onlist = 1; + ctxt->etextp->next = s; + ctxt->etextp = s; } } } @@ -712,6 +703,9 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn) else diag("invalid rela size %d", rp->siz); } + if(rp->siz == 4) + rp->add = (int32)rp->add; + //print("rel %s %d %d %s %#llx\n", sect->sym->name, rp->type, rp->siz, rp->sym->name, rp->add); } qsort(r, n, sizeof r[0], rbyoff); // just in case @@ -761,7 +755,7 @@ map(ElfObj *obj, ElfSect *sect) static int readsym(ElfObj *obj, int i, ElfSym *sym, int needSym) { - Sym *s; + LSym *s; if(i >= obj->nsymtab || i < 0) { werrstr("invalid elf symbol index"); @@ -808,7 +802,7 @@ readsym(ElfObj *obj, int i, ElfSym *sym, int needSym) switch(sym->bind) { case ElfSymBindGlobal: if(needSym) { - s = lookup(sym->name, 0); + s = linklookup(ctxt, sym->name, 0); // for global scoped hidden symbols we should insert it into // symbol hash table, but mark them as hidden. // __i686.get_pc_thunk.bx is allowed to be duplicated, to @@ -828,13 +822,13 @@ readsym(ElfObj *obj, int i, ElfSym *sym, int needSym) // local names and hidden visiblity global names are unique // and should only reference by its index, not name, so we // don't bother to add them into hash table - s = newsym(sym->name, version); + s = linknewsym(ctxt, sym->name, ctxt->version); s->type |= SHIDDEN; } break; case ElfSymBindWeak: if(needSym) { - s = newsym(sym->name, 0); + s = linknewsym(ctxt, sym->name, 0); if(sym->other == 2) s->type |= SHIDDEN; } diff --git a/src/cmd/ld/ldmacho.c b/src/cmd/ld/ldmacho.c index e0f5405f6..413dedabd 100644 --- a/src/cmd/ld/ldmacho.c +++ b/src/cmd/ld/ldmacho.c @@ -102,7 +102,7 @@ struct MachoSect uint32 flags; uint32 res1; uint32 res2; - Sym *sym; + LSym *sym; MachoRel *rel; }; @@ -138,7 +138,7 @@ struct MachoSym uint16 desc; char kind; uint64 value; - Sym *sym; + LSym *sym; }; struct MachoDysymtab @@ -432,7 +432,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) int64 base; MachoSect *sect; MachoRel *rel; - Sym *s, *s1, *outer; + LSym *s, *s1, *outer; MachoCmd *c; MachoSymtab *symtab; MachoDysymtab *dsymtab; @@ -440,7 +440,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) Reloc *r, *rp; char *name; - version++; + ctxt->version++; base = Boffset(f); if(Bread(f, hdr, sizeof hdr) != sizeof hdr) goto bad; @@ -507,6 +507,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) c = nil; symtab = nil; dsymtab = nil; + USED(dsymtab); for(i=0; ie32(cmdp); sz = e->e32(cmdp+4); @@ -566,7 +567,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) if(strcmp(sect->name, "__eh_frame") == 0) continue; name = smprint("%s(%s/%s)", pkg, sect->segname, sect->name); - s = lookup(name, version); + s = linklookup(ctxt, name, ctxt->version); if(s->type != 0) { werrstr("duplicate %s/%s", sect->segname, sect->name); goto bad; @@ -609,8 +610,8 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) name++; v = 0; if(!(sym->type&N_EXT)) - v = version; - s = lookup(name, v); + v = ctxt->version; + s = linklookup(ctxt, name, v); if(!(sym->type&N_EXT)) s->dupok = 1; sym->sym = s; @@ -640,22 +641,9 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) if(!(s->cgoexport & CgoExportDynamic)) s->dynimplib = 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; + if(s->external && !s->dupok) + diag("%s: duplicate definition of %s", pn, s->name); + s->external = 1; } sym->sym = s; } @@ -667,7 +655,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) if((s = sect->sym) == S) continue; if(s->sub) { - s->sub = listsort(s->sub, valuecmp, offsetof(Sym, sub)); + s->sub = listsort(s->sub, valuecmp, offsetof(LSym, sub)); // assign sizes, now that we know symbols in sorted order. for(s1 = s->sub; s1 != S; s1 = s1->sub) { @@ -678,14 +666,20 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) } } if(s->type == STEXT) { - if(etextp) - etextp->next = s; + if(s->onlist) + sysfatal("symbol %s listed multiple times", s->name); + s->onlist = 1; + if(ctxt->etextp) + ctxt->etextp->next = s; else - textp = s; - etextp = s; + ctxt->textp = s; + ctxt->etextp = s; for(s1 = s->sub; s1 != S; s1 = s1->sub) { - etextp->next = s1; - etextp = s1; + if(s1->onlist) + sysfatal("symbol %s listed multiple times", s1->name); + s1->onlist = 1; + ctxt->etextp->next = s1; + ctxt->etextp = s1; } } } @@ -743,7 +737,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) // 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->type = R_PCREL; rp->add += (rp->off+4) - ((rel+1)->value - sect->addr); // now consider the desired symbol. diff --git a/src/cmd/ld/ldpe.c b/src/cmd/ld/ldpe.c index 6bcda2cb6..f6eda900d 100644 --- a/src/cmd/ld/ldpe.c +++ b/src/cmd/ld/ldpe.c @@ -102,14 +102,14 @@ struct PeSym { uint16 type; uint8 sclass; uint8 aux; - Sym* sym; + LSym* sym; }; struct PeSect { char* name; uchar* base; uint64 size; - Sym* sym; + LSym* sym; IMAGE_SECTION_HEADER sh; }; @@ -141,7 +141,7 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn) PeSect *sect, *rsect; IMAGE_SECTION_HEADER sh; uchar symbuf[18]; - Sym *s; + LSym *s; Reloc *r, *rp; PeSym *sym; @@ -150,7 +150,7 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn) Bprint(&bso, "%5.2f ldpe %s\n", cputime(), pn); sect = nil; - version++; + ctxt->version++; base = Boffset(f); obj = mal(sizeof *obj); @@ -222,7 +222,7 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn) goto bad; name = smprint("%s(%s)", pkg, sect->name); - s = lookup(name, version); + s = linklookup(ctxt, name, ctxt->version); free(name); switch(sect->sh.Characteristics&(IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_CNT_INITIALIZED_DATA| IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE)) { @@ -290,18 +290,18 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn) case IMAGE_REL_AMD64_REL32: case IMAGE_REL_AMD64_ADDR32: // R_X86_64_PC32 case IMAGE_REL_AMD64_ADDR32NB: - rp->type = D_PCREL; + rp->type = R_PCREL; rp->add = (int32)le32(rsect->base+rp->off); break; case IMAGE_REL_I386_DIR32NB: case IMAGE_REL_I386_DIR32: - rp->type = D_ADDR; + rp->type = R_ADDR; // load addend from image - rp->add = le32(rsect->base+rp->off); + rp->add = (int32)le32(rsect->base+rp->off); break; case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64 rp->siz = 8; - rp->type = D_ADDR; + rp->type = R_ADDR; // load addend from image rp->add = le64(rsect->base+rp->off); break; @@ -366,21 +366,9 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn) s->size = 4; s->outer = sect->sym; if(sect->sym->type == STEXT) { - Prog *p; - - if(s->text != P) + if(s->external && !s->dupok) 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; + s->external = 1; } } @@ -391,16 +379,22 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn) if(s == S) continue; if(s->sub) - s->sub = listsort(s->sub, valuecmp, offsetof(Sym, sub)); + s->sub = listsort(s->sub, valuecmp, offsetof(LSym, sub)); if(s->type == STEXT) { - if(etextp) - etextp->next = s; + if(s->onlist) + sysfatal("symbol %s listed multiple times", s->name); + s->onlist = 1; + if(ctxt->etextp) + ctxt->etextp->next = s; else - textp = s; - etextp = s; + ctxt->textp = s; + ctxt->etextp = s; for(s = s->sub; s != S; s = s->sub) { - etextp->next = s; - etextp = s; + if(s->onlist) + sysfatal("symbol %s listed multiple times", s->name); + s->onlist = 1; + ctxt->etextp->next = s; + ctxt->etextp = s; } } } @@ -430,7 +424,7 @@ map(PeObj *obj, PeSect *sect) static int readsym(PeObj *obj, int i, PeSym **y) { - Sym *s; + LSym *s; PeSym *sym; char *name, *p; @@ -464,12 +458,12 @@ readsym(PeObj *obj, int i, PeSym **y) case IMAGE_SYM_DTYPE_NULL: switch(sym->sclass) { case IMAGE_SYM_CLASS_EXTERNAL: //global - s = lookup(name, 0); + s = linklookup(ctxt, name, 0); break; case IMAGE_SYM_CLASS_NULL: case IMAGE_SYM_CLASS_STATIC: case IMAGE_SYM_CLASS_LABEL: - s = lookup(name, version); + s = linklookup(ctxt, name, ctxt->version); s->dupok = 1; break; default: diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c index da522dc0c..da6194e4f 100644 --- a/src/cmd/ld/lib.c +++ b/src/cmd/ld/lib.c @@ -32,10 +32,14 @@ #include "l.h" #include "lib.h" #include "../ld/elf.h" +#include "../ld/dwarf.h" #include "../../pkg/runtime/stack.h" #include "../../pkg/runtime/funcdata.h" #include +#if !(defined(_WIN32) || defined(PLAN9)) +#include +#endif enum { @@ -48,18 +52,9 @@ int iconv(Fmt*); char symname[] = SYMDEF; char pkgname[] = "__.PKGDEF"; -char** libdir; -int nlibdir = 0; -static int maxlibdir = 0; static int cout = -1; -// symbol version, incremented each time a file is loaded. -// version==1 is reserved for savehist. -enum -{ - HistVersion = 1, -}; -int version = HistVersion; +extern int version; // Set if we see an object compiled by the host compiler that is not // from a package that is known to support internal linking mode. @@ -77,15 +72,32 @@ Lflag(char *arg) { char **p; - if(nlibdir >= maxlibdir) { - if (maxlibdir == 0) - maxlibdir = 8; + if(ctxt->nlibdir >= ctxt->maxlibdir) { + if (ctxt->maxlibdir == 0) + ctxt->maxlibdir = 8; else - maxlibdir *= 2; - p = erealloc(libdir, maxlibdir * sizeof(*p)); - libdir = p; + ctxt->maxlibdir *= 2; + p = erealloc(ctxt->libdir, ctxt->maxlibdir * sizeof(*p)); + ctxt->libdir = p; } - libdir[nlibdir++] = arg; + ctxt->libdir[ctxt->nlibdir++] = arg; +} + +/* + * Unix doesn't like it when we write to a running (or, sometimes, + * recently run) binary, so remove the output file before writing it. + * On Windows 7, remove() can force a subsequent create() to fail. + * S_ISREG() does not exist on Plan 9. + */ +static void +mayberemoveoutfile(void) +{ +#if !(defined(_WIN32) || defined(PLAN9)) + struct stat st; + if(lstat(outfile, &st) == 0 && !S_ISREG(st.st_mode)) + return; +#endif + remove(outfile); } void @@ -93,12 +105,11 @@ libinit(void) { char *suffix, *suffixsep; + funcalign = FuncAlign; fmtinstall('i', iconv); fmtinstall('Y', Yconv); fmtinstall('Z', Zconv); mywhatsys(); // get goroot, goarch, goos - if(strcmp(goarch, thestring) != 0) - print("goarch is not known: %s\n", goarch); // add goroot to the end of the libdir list. suffix = ""; @@ -112,12 +123,7 @@ libinit(void) } Lflag(smprint("%s/pkg/%s_%s%s%s", goroot, goos, goarch, suffixsep, suffix)); - // Unix doesn't like it when we write to a running (or, sometimes, - // recently run) binary, so remove the output file before writing it. - // On Windows 7, remove() can force the following create() to fail. -#ifndef _WIN32 - remove(outfile); -#endif + mayberemoveoutfile(); cout = create(outfile, 1, 0775); if(cout < 0) { diag("cannot create %s: %r", outfile); @@ -132,7 +138,7 @@ libinit(void) sprint(INITENTRY, "_rt0_%s_%s_lib", goarch, goos); } } - lookup(INITENTRY, 0)->type = SXREF; + linklookup(ctxt, INITENTRY, 0)->type = SXREF; } void @@ -140,152 +146,12 @@ errorexit(void) { if(nerrors) { if(cout >= 0) - remove(outfile); + mayberemoveoutfile(); exits("error"); } exits(0); } -void -addlib(char *src, char *obj) -{ - char name[1024], pname[1024], comp[256], *p; - int i, search; - - if(histfrogp <= 0) - return; - - search = 0; - if(histfrog[0]->name[1] == '/') { - sprint(name, ""); - i = 1; - } else - if(isalpha((uchar)histfrog[0]->name[1]) && histfrog[0]->name[2] == ':') { - strcpy(name, histfrog[0]->name+1); - i = 1; - } else - if(histfrog[0]->name[1] == '.') { - sprint(name, "."); - i = 0; - } else { - sprint(name, ""); - i = 0; - search = 1; - } - - for(; iname+1); - for(;;) { - p = strstr(comp, "$O"); - if(p == 0) - break; - memmove(p+1, p+2, strlen(p+2)+1); - p[0] = thechar; - } - for(;;) { - p = strstr(comp, "$M"); - if(p == 0) - break; - if(strlen(comp)+strlen(thestring)-2+1 >= sizeof comp) { - diag("library component too long"); - return; - } - memmove(p+strlen(thestring), p+2, strlen(p+2)+1); - memmove(p, thestring, strlen(thestring)); - } - if(strlen(name) + strlen(comp) + 3 >= sizeof(name)) { - diag("library component too long"); - return; - } - if(i > 0 || !search) - strcat(name, "/"); - 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 runtime.a for search - if(p != nil) - *p = '.'; - - if(search) { - // try dot, -L "libdir", and then goroot. - for(i=0; i= 0) - break; - } - }else - strcpy(pname, name); - cleanname(pname); - - /* runtime.a -> runtime */ - if(p != nil) - *p = '\0'; - - if(debug['v'] > 1) - Bprint(&bso, "%5.2f addlib: %s %s pulls in %s\n", cputime(), obj, src, pname); - - addlibpath(src, obj, pname, name); -} - -/* - * add library to library list. - * srcref: src file referring to package - * objref: object file referring to package - * file: object file, e.g., /home/rsc/go/pkg/container/vector.a - * pkg: package import path, e.g. container/vector - */ -void -addlibpath(char *srcref, char *objref, char *file, char *pkg) -{ - int i; - Library *l; - char *p; - - for(i=0; i 1) - Bprint(&bso, "%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s\n", - cputime(), srcref, objref, file, pkg); - - if(libraryp == nlibrary){ - nlibrary = 50 + 2*libraryp; - library = erealloc(library, sizeof library[0] * nlibrary); - } - - l = &library[libraryp++]; - - p = mal(strlen(objref) + 1); - strcpy(p, objref); - l->objref = p; - - p = mal(strlen(srcref) + 1); - strcpy(p, srcref); - l->srcref = p; - - p = mal(strlen(file) + 1); - strcpy(p, file); - l->file = p; - - p = mal(strlen(pkg) + 1); - strcpy(p, pkg); - l->pkg = p; -} - void loadinternal(char *name) { @@ -293,12 +159,12 @@ loadinternal(char *name) int i, found; found = 0; - for(i=0; inlibdir; i++) { + snprint(pname, sizeof pname, "%s/%s.a", ctxt->libdir[i], name); if(debug['v']) Bprint(&bso, "searching for %s.a in %s\n", name, pname); if(access(pname, AEXIST) >= 0) { - addlibpath("internal", "internal", pname, name); + addlibpath(ctxt, "internal", "internal", pname, name); found = 1; break; } @@ -311,12 +177,13 @@ void loadlib(void) { int i, w, x; - Sym *s, *gmsym; + LSym *s, *gmsym; + char* cgostrsym; if(flag_shared) { - s = lookup("runtime.islibrary", 0); + s = linklookup(ctxt, "runtime.islibrary", 0); s->dupok = 1; - adduint8(s, 1); + adduint8(ctxt, s, 1); } loadinternal("runtime"); @@ -324,27 +191,36 @@ loadlib(void) loadinternal("math"); if(flag_race) loadinternal("runtime/race"); - if(linkmode == LinkExternal) { + + for(i=0; ilibraryp; i++) { + if(debug['v'] > 1) + Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), ctxt->library[i].file, ctxt->library[i].objref); + iscgo |= strcmp(ctxt->library[i].pkg, "runtime/cgo") == 0; + objfile(ctxt->library[i].file, ctxt->library[i].pkg); + } + + if(linkmode == LinkExternal && !iscgo) { // This indicates a user requested -linkmode=external. // The startup code uses an import of runtime/cgo to decide // whether to initialize the TLS. So give it one. This could // be handled differently but it's an unusual case. loadinternal("runtime/cgo"); + if(i < ctxt->libraryp) + objfile(ctxt->library[i].file, ctxt->library[i].pkg); + // Pretend that we really imported the package. - // This will do no harm if we did in fact import it. - s = lookup("go.importpath.runtime/cgo.", 0); + s = linklookup(ctxt, "go.importpath.runtime/cgo.", 0); s->type = SDATA; s->dupok = 1; s->reachable = 1; - } - for(i=0; i 1) - Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i].file, library[i].objref); - iscgo |= strcmp(library[i].pkg, "runtime/cgo") == 0; - objfile(library[i].file, library[i].pkg); + // Provided by the code that imports the package. + // Since we are simulating the import, we have to provide this string. + cgostrsym = "go.string.\"runtime/cgo\""; + if(linkrlookup(ctxt, cgostrsym, 0) == nil) + addstrdata(cgostrsym, "runtime/cgo"); } - + if(linkmode == LinkAuto) { if(iscgo && externalobj) linkmode = LinkExternal; @@ -355,7 +231,7 @@ loadlib(void) if(linkmode == LinkInternal) { // Drop all the cgo_import_static declarations. // Turns out we won't be needing them. - for(s = allsym; s != S; s = s->allsym) + for(s = ctxt->allsym; s != S; s = s->allsym) if(s->type == SHOSTOBJ) { // If a symbol was marked both // cgo_import_static and cgo_import_dynamic, @@ -368,14 +244,12 @@ loadlib(void) } } - gmsym = lookup("runtime.tlsgm", 0); + gmsym = linklookup(ctxt, "runtime.tlsgm", 0); gmsym->type = STLSBSS; gmsym->size = 2*PtrSize; gmsym->hide = 1; - if(linkmode == LinkExternal && iself && HEADTYPE != Hopenbsd) - gmsym->reachable = 1; - else - gmsym->reachable = 0; + gmsym->reachable = 1; + ctxt->gmsym = gmsym; // Now that we know the link mode, trim the dynexp list. x = CgoExportDynamic; @@ -402,7 +276,9 @@ loadlib(void) // // Exception: on OS X, programs such as Shark only work with dynamic // binaries, so leave it enabled on OS X (Mach-O) binaries. - if(!flag_shared && !havedynamic && HEADTYPE != Hdarwin) + // Also leave it enabled on Solaris which doesn't support + // statically linked binaries. + if(!flag_shared && !havedynamic && HEADTYPE != Hdarwin && HEADTYPE != Hsolaris) debug['d'] = 1; importcycles(); @@ -412,8 +288,8 @@ loadlib(void) * look for the next file in an archive. * adapted from libmach. */ -int -nextar(Biobuf *bp, int off, struct ar_hdr *a) +static vlong +nextar(Biobuf *bp, vlong off, struct ar_hdr *a) { int r; int32 arsize; @@ -443,7 +319,7 @@ nextar(Biobuf *bp, int off, struct ar_hdr *a) void objfile(char *file, char *pkg) { - int32 off, l; + vlong off, l; Biobuf *f; char magbuf[SARMAG]; char pname[150]; @@ -470,25 +346,24 @@ objfile(char *file, char *pkg) return; } - /* skip over __.GOSYMDEF */ + /* skip over optional __.GOSYMDEF and process __.PKGDEF */ off = Boffset(f); - if((l = nextar(f, off, &arhdr)) <= 0) { + l = nextar(f, off, &arhdr); + if(l <= 0) { diag("%s: short read on archive file symbol header", file); goto out; } - if(strncmp(arhdr.name, symname, strlen(symname))) { - diag("%s: first entry not symbol header", file); - goto out; - } - 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, symname, strlen(symname)) == 0) { + off += l; + l = nextar(f, off, &arhdr); + if(l <= 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); + diag("%s: cannot find package header", file); goto out; } off += l; @@ -539,7 +414,7 @@ dowrite(int fd, char *p, int n) while(n > 0) { m = write(fd, p, n); if(m <= 0) { - cursym = S; + ctxt->cursym = S; diag("write error: %r"); errorexit(); } @@ -628,7 +503,7 @@ hostobjs(void) h = &hostobj[i]; f = Bopen(h->file, OREAD); if(f == nil) { - cursym = S; + ctxt->cursym = S; diag("cannot reopen %s: %r", h->pn); errorexit(); } @@ -697,7 +572,7 @@ hostlink(void) p = strchr(p + 1, ' '); } - argv = malloc((13+nhostobj+nldflag+c)*sizeof argv[0]); + argv = malloc((14+nhostobj+nldflag+c)*sizeof argv[0]); argc = 0; if(extld == nil) extld = "gcc"; @@ -720,6 +595,8 @@ hostlink(void) } if(HEADTYPE == Hdarwin) argv[argc++] = "-Wl,-no_pie,-pagezero_size,4000000"; + if(HEADTYPE == Hopenbsd) + argv[argc++] = "-Wl,-nopie"; if(iself && AssumeGoldLinker) argv[argc++] = "-Wl,--rosegment"; @@ -738,13 +615,16 @@ hostlink(void) if(iself) argv[argc++] = "-rdynamic"; + if(strstr(argv[0], "clang") != nil) + argv[argc++] = "-Qunused-arguments"; + // already wrote main object file // copy host objects to temporary directory for(i=0; ifile, OREAD); if(f == nil) { - cursym = S; + ctxt->cursym = S; diag("cannot reopen %s: %r", h->pn); errorexit(); } @@ -753,7 +633,7 @@ hostlink(void) argv[argc++] = p; w = create(p, 1, 0775); if(w < 0) { - cursym = S; + ctxt->cursym = S; diag("cannot create %s: %r", p); errorexit(); } @@ -765,7 +645,7 @@ hostlink(void) len -= n; } if(close(w) < 0) { - cursym = S; + ctxt->cursym = S; diag("cannot write %s: %r", p); errorexit(); } @@ -783,6 +663,20 @@ hostlink(void) if(*p == '\0') break; argv[argc++] = p; + + // clang, unlike GCC, passes -rdynamic to the linker + // even when linking with -static, causing a linker + // error when using GNU ld. So take out -rdynamic if + // we added it. We do it in this order, rather than + // only adding -rdynamic later, so that -extldflags + // can override -rdynamic without using -static. + if(iself && strncmp(p, "-static", 7) == 0 && (p[7]==' ' || p[7]=='\0')) { + for(i=0; icursym = S; diag("%s: running %s failed: %r", argv0, argv[0]); errorexit(); } @@ -866,8 +760,8 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, char *file, int whence) return; } - // First, check that the basic goos, string, and version match. - t = smprint("%s %s %s ", goos, thestring, getgoversion()); + // First, check that the basic goos, goarch, and version match. + t = smprint("%s %s %s ", goos, getgoarch(), getgoversion()); line[n] = ' '; if(strncmp(line+10, t, strlen(t)) != 0 && !debug['f']) { line[n] = '\0'; @@ -913,7 +807,7 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, char *file, int whence) ldpkg(f, pkg, import1 - import0 - 2, pn, whence); // -2 for !\n Bseek(f, import1, 0); - ldobj1(f, pkg, eof - Boffset(f), pn); + ldobjfile(ctxt, f, pkg, eof - Boffset(f), pn); free(pn); return; @@ -922,318 +816,12 @@ eof: free(pn); } -Sym* -newsym(char *symb, int v) -{ - Sym *s; - int l; - - l = strlen(symb) + 1; - s = mal(sizeof(*s)); - if(debug['v'] > 1) - Bprint(&bso, "newsym %s\n", symb); - - s->dynid = -1; - s->plt = -1; - s->got = -1; - s->name = mal(l + 1); - memmove(s->name, symb, l); - - s->type = 0; - s->version = v; - s->value = 0; - s->sig = 0; - s->size = 0; - nsymbol++; - - s->allsym = allsym; - allsym = s; - - return s; -} - -static Sym* -_lookup(char *symb, int v, int creat) -{ - Sym *s; - char *p; - uint32 h; - int c; - - h = v; - for(p=symb; c = *p; p++) - h = h+h+h + c; - // 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->hash) - if(strcmp(s->name, symb) == 0) - return s; - if(!creat) - return nil; - - s = newsym(symb, v); - s->extname = s->name; - s->hash = hash[h]; - hash[h] = s; - - return s; -} - -Sym* -lookup(char *name, int v) -{ - return _lookup(name, v, 1); -} - -// read-only lookup -Sym* -rlookup(char *name, int v) -{ - return _lookup(name, v, 0); -} - -void -copyhistfrog(char *buf, int nbuf) -{ - char *p, *ep; - int i; - - p = buf; - ep = buf + nbuf; - for(i=0; iname+1); - if(i+1name = mal(2*(histfrogp+1) + 1); - - u->asym = s; - u->type = type; - u->aoffset = line; - u->link = curhist; - curhist = u; - - s->name[0] = 0; - j = 1; - for(i=0; ivalue; - s->name[j+0] = k>>8; - s->name[j+1] = k; - j += 2; - } - s->name[j] = 0; - s->name[j+1] = 0; -} - -void -histtoauto(void) -{ - Auto *l; - - while(l = curhist) { - curhist = l->link; - l->link = curauto; - curauto = l; - } -} - -void -collapsefrog(Sym *s) -{ - int i; - - /* - * bad encoding of path components only allows - * MAXHIST components. if there is an overflow, - * first try to collapse xxx/.. - */ - for(i=1; iname+1, "..") == 0) { - memmove(histfrog+i-1, histfrog+i+1, - (histfrogp-i-1)*sizeof(histfrog[0])); - histfrogp--; - goto out; - } - - /* - * next try to collapse . - */ - for(i=0; iname+1, ".") == 0) { - memmove(histfrog+i, histfrog+i+1, - (histfrogp-i-1)*sizeof(histfrog[0])); - goto out; - } - - /* - * last chance, just truncate from front - */ - memmove(histfrog+0, histfrog+1, - (histfrogp-1)*sizeof(histfrog[0])); - -out: - histfrog[histfrogp-1] = s; -} - -void -nuxiinit(void) -{ - int i, c; - - for(i=0; i<4; i++) { - c = find1(0x04030201L, i+1); - if(i < 2) - inuxi2[i] = c; - if(i < 1) - inuxi1[i] = c; - inuxi4[i] = c; - 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; - } - if(debug['v']) { - Bprint(&bso, "inuxi = "); - for(i=0; i<1; i++) - Bprint(&bso, "%d", inuxi1[i]); - Bprint(&bso, " "); - for(i=0; i<2; i++) - Bprint(&bso, "%d", inuxi2[i]); - Bprint(&bso, " "); - for(i=0; i<4; i++) - Bprint(&bso, "%d", inuxi4[i]); - Bprint(&bso, " "); - for(i=0; i<8; i++) - Bprint(&bso, "%d", inuxi8[i]); - Bprint(&bso, "\nfnuxi = "); - for(i=0; i<4; i++) - Bprint(&bso, "%d", fnuxi4[i]); - Bprint(&bso, " "); - for(i=0; i<8; i++) - Bprint(&bso, "%d", fnuxi8[i]); - Bprint(&bso, "\n"); - } - Bflush(&bso); -} - -int -find1(int32 l, int c) -{ - char *p; - int i; - - p = (char*)&l; - for(i=0; i<4; i++) - if(*p++ == c) - return i; - return 0; -} - -int -find2(int32 l, int c) -{ - union { - int32 l; - short p[2]; - } u; - short *p; - int i; - - u.l = l; - p = u.p; - for(i=0; i<4; i+=2) { - if(((*p >> 8) & 0xff) == c) - return i; - if((*p++ & 0xff) == c) - return i+1; - } - return 0; -} - -int32 -ieeedtof(Ieee *e) -{ - int exp; - int32 v; - - if(e->h == 0) - return 0; - exp = (e->h>>20) & ((1L<<11)-1L); - exp -= (1L<<10) - 2L; - v = (e->h & 0xfffffL) << 3; - v |= (e->l >> 29) & 0x7L; - if((e->l >> 28) & 1) { - v++; - if(v & 0x800000L) { - v = (v & 0x7fffffL) >> 1; - exp++; - } - } - if(-148 <= exp && exp <= -126) { - v |= 1<<23; - v >>= -125 - exp; - exp = -126; - } - else if(exp < -148 || exp >= 130) - diag("double fp to single fp overflow: %.17g", ieeedtod(e)); - v |= ((exp + 126) & 0xffL) << 23; - v |= e->h & 0x80000000L; - return v; -} - -double -ieeedtod(Ieee *ieeep) -{ - Ieee e; - double fr; - int exp; - - if(ieeep->h & (1L<<31)) { - e.h = ieeep->h & ~(1L<<31); - e.l = ieeep->l; - return -ieeedtod(&e); - } - if(ieeep->l == 0 && ieeep->h == 0) - return 0; - exp = (ieeep->h>>20) & ((1L<<11)-1L); - exp -= (1L<<10) - 2L; - fr = ieeep->l & ((1L<<16)-1L); - fr /= 1L<<16; - fr += (ieeep->l>>16) & ((1L<<16)-1L); - fr /= 1L<<16; - if(exp == -(1L<<10) - 2L) { - fr += (ieeep->h & (1L<<20)-1L); - exp++; - } else - fr += (ieeep->h & (1L<<20)-1L) | (1L<<20); - fr /= 1L<<21; - return ldexp(fr, exp); -} - void zerosig(char *sp) { - Sym *s; + LSym *s; - s = lookup(sp, 0); + s = linklookup(ctxt, sp, 0); s->sig = 0; } @@ -1242,7 +830,10 @@ mywhatsys(void) { goroot = getgoroot(); goos = getgoos(); - goarch = thestring; // ignore $GOARCH - we know who we are + goarch = getgoarch(); + + if(strncmp(goarch, thestring, strlen(thestring)) != 0) + sysfatal("cannot use %cc with GOARCH=%s", thechar, goarch); } int @@ -1303,7 +894,8 @@ unmal(void *v, uint32 n) * Invalid bytes turn into %xx. Right now the only bytes that need * escaping are %, ., and ", but we escape all control characters too. * - * Must be same as ../gc/subr.c:/^pathtoprefix. + * If you edit this, edit ../gc/subr.c:/^pathtoprefix too. + * If you edit this, edit ../../pkg/debug/goobj/read.go:/importPathToPrefix too. */ static char* pathtoprefix(char *s) @@ -1357,13 +949,6 @@ 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) { @@ -1381,235 +966,6 @@ addsection(Segment *seg, char *name, int rwx) return sect; } -void -addvarint(Sym *s, uint32 val) -{ - int32 n; - uint32 v; - uchar *p; - - n = 0; - for(v = val; v >= 0x80; v >>= 7) - n++; - n++; - - symgrow(s, s->np+n); - - p = s->p + s->np - n; - for(v = val; v >= 0x80; v >>= 7) - *p++ = v | 0x80; - *p = v; -} - -// funcpctab appends to dst a pc-value table mapping the code in func to the values -// returned by valfunc parameterized by arg. The invocation of valfunc to update the -// current value is, for each p, -// -// val = valfunc(func, val, p, 0, arg); -// record val as value at p->pc; -// val = valfunc(func, val, p, 1, arg); -// -// where func is the function, val is the current value, p is the instruction being -// considered, and arg can be used to further parameterize valfunc. -void -funcpctab(Sym *dst, Sym *func, char *desc, int32 (*valfunc)(Sym*, int32, Prog*, int32, int32), int32 arg) -{ - int dbg, i, start; - int32 oldval, val, started; - uint32 delta; - vlong pc; - Prog *p; - - // To debug a specific function, uncomment second line and change name. - dbg = 0; - //dbg = strcmp(func->name, "main.main") == 0; - - debug['O'] += dbg; - - start = dst->np; - - if(debug['O']) - Bprint(&bso, "funcpctab %s -> %s [valfunc=%s]\n", func->name, dst->name, desc); - - val = -1; - oldval = val; - pc = func->value; - - if(debug['O']) - Bprint(&bso, "%6llux %6d %P\n", pc, val, func->text); - - started = 0; - for(p=func->text; p != P; p = p->link) { - // Update val. If it's not changing, keep going. - val = valfunc(func, val, p, 0, arg); - if(val == oldval && started) { - val = valfunc(func, val, p, 1, arg); - if(debug['O']) - Bprint(&bso, "%6llux %6s %P\n", (vlong)p->pc, "", p); - continue; - } - - // If the pc of the next instruction is the same as the - // pc of this instruction, this instruction is not a real - // instruction. Keep going, so that we only emit a delta - // for a true instruction boundary in the program. - if(p->link && p->link->pc == p->pc) { - val = valfunc(func, val, p, 1, arg); - if(debug['O']) - Bprint(&bso, "%6llux %6s %P\n", (vlong)p->pc, "", p); - continue; - } - - // The table is a sequence of (value, pc) pairs, where each - // pair states that the given value is in effect from the current position - // up to the given pc, which becomes the new current position. - // To generate the table as we scan over the program instructions, - // we emit a "(value" when pc == func->value, and then - // each time we observe a change in value we emit ", pc) (value". - // When the scan is over, we emit the closing ", pc)". - // - // The table is delta-encoded. The value deltas are signed and - // transmitted in zig-zag form, where a complement bit is placed in bit 0, - // and the pc deltas are unsigned. Both kinds of deltas are sent - // as variable-length little-endian base-128 integers, - // where the 0x80 bit indicates that the integer continues. - - if(debug['O']) - Bprint(&bso, "%6llux %6d %P\n", (vlong)p->pc, val, p); - - if(started) { - addvarint(dst, (p->pc - pc) / MINLC); - pc = p->pc; - } - delta = val - oldval; - if(delta>>31) - delta = 1 | ~(delta<<1); - else - delta <<= 1; - addvarint(dst, delta); - oldval = val; - started = 1; - val = valfunc(func, val, p, 1, arg); - } - - if(started) { - if(debug['O']) - Bprint(&bso, "%6llux done\n", (vlong)func->value+func->size); - addvarint(dst, (func->value+func->size - pc) / MINLC); - addvarint(dst, 0); // terminator - } - - if(debug['O']) { - Bprint(&bso, "wrote %d bytes\n", dst->np - start); - for(i=start; inp; i++) - Bprint(&bso, " %02ux", dst->p[i]); - Bprint(&bso, "\n"); - } - - debug['O'] -= dbg; -} - -// pctofileline computes either the file number (arg == 0) -// or the line number (arg == 1) to use at p. -// Because p->lineno applies to p, phase == 0 (before p) -// takes care of the update. -static int32 -pctofileline(Sym *sym, int32 oldval, Prog *p, int32 phase, int32 arg) -{ - int32 f, l; - - if(p->as == ATEXT || p->as == ANOP || p->as == AUSEFIELD || p->line == 0 || phase == 1) - return oldval; - getline(sym->hist, p->line, &f, &l); - if(f == 0) { - // print("getline failed for %s %P\n", cursym->name, p); - return oldval; - } - if(arg == 0) - return f; - return l; -} - -// pctospadj computes the sp adjustment in effect. -// It is oldval plus any adjustment made by p itself. -// The adjustment by p takes effect only after p, so we -// apply the change during phase == 1. -static int32 -pctospadj(Sym *sym, int32 oldval, Prog *p, int32 phase, int32 arg) -{ - USED(arg); - USED(sym); - - if(oldval == -1) // starting - oldval = 0; - if(phase == 0) - return oldval; - if(oldval + p->spadj < -10000 || oldval + p->spadj > 1100000000) { - diag("overflow in spadj: %d + %d = %d", oldval, p->spadj, oldval + p->spadj); - errorexit(); - } - return oldval + p->spadj; -} - -// pctopcdata computes the pcdata value in effect at p. -// A PCDATA instruction sets the value in effect at future -// non-PCDATA instructions. -// Since PCDATA instructions have no width in the final code, -// it does not matter which phase we use for the update. -static int32 -pctopcdata(Sym *sym, int32 oldval, Prog *p, int32 phase, int32 arg) -{ - USED(sym); - - if(phase == 0 || p->as != APCDATA || p->from.offset != arg) - return oldval; - if((int32)p->to.offset != p->to.offset) { - diag("overflow in PCDATA instruction: %P", p); - errorexit(); - } - return p->to.offset; -} - -#define LOG 5 -void -mkfwd(void) -{ - Prog *p; - int i; - int32 dwn[LOG], cnt[LOG]; - Prog *lst[LOG]; - - for(i=0; inext) { - 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) { @@ -1652,7 +1008,7 @@ Endian le = { le16, le32, le64 }; typedef struct Chain Chain; struct Chain { - Sym *sym; + LSym *sym; Chain *up; int limit; // limit on entry to sym }; @@ -1660,67 +1016,87 @@ struct Chain static int stkcheck(Chain*, int); static void stkprint(Chain*, int); static void stkbroke(Chain*, int); -static Sym *morestack; -static Sym *newstack; +static LSym *morestack; +static LSym *newstack; enum { HasLinkRegister = (thechar == '5'), - CallSize = (!HasLinkRegister)*PtrSize, // bytes of stack required for a call }; +// TODO: Record enough information in new object files to +// allow stack checks here. + +static int +callsize(void) +{ + if(thechar == '5') + return 0; + return RegSize; +} + void dostkcheck(void) { Chain ch; - Sym *s; + LSym *s; - morestack = lookup("runtime.morestack", 0); - newstack = lookup("runtime.newstack", 0); - - // First the nosplits on their own. - for(s = textp; s != nil; s = s->next) { - if(s->text == nil || s->text->link == nil || (s->text->textflag & NOSPLIT) == 0) + morestack = linklookup(ctxt, "runtime.morestack", 0); + newstack = linklookup(ctxt, "runtime.newstack", 0); + + // Every splitting function ensures that there are at least StackLimit + // bytes available below SP when the splitting prologue finishes. + // If the splitting function calls F, then F begins execution with + // at least StackLimit - callsize() bytes available. + // Check that every function behaves correctly with this amount + // of stack, following direct calls in order to piece together chains + // of non-splitting functions. + ch.up = nil; + ch.limit = StackLimit - callsize(); + + // Check every function, but do the nosplit functions in a first pass, + // to make the printed failure chains as short as possible. + for(s = ctxt->textp; s != nil; s = s->next) { + // runtime.racesymbolizethunk is called from gcc-compiled C + // code running on the operating system thread stack. + // It uses more than the usual amount of stack but that's okay. + if(strcmp(s->name, "runtime.racesymbolizethunk") == 0) continue; - cursym = s; - ch.up = nil; + + if(s->nosplit) { + ctxt->cursym = s; ch.sym = s; - ch.limit = StackLimit - CallSize; stkcheck(&ch, 0); - s->stkcheck = 1; } - - // Check calling contexts. - // Some nosplits get called a little further down, - // like newproc and deferproc. We could hard-code - // that knowledge but it's more robust to look at - // the actual call sites. - for(s = textp; s != nil; s = s->next) { - if(s->text == nil || s->text->link == nil || (s->text->textflag & NOSPLIT) != 0) - continue; - cursym = s; - ch.up = nil; + } + for(s = ctxt->textp; s != nil; s = s->next) { + if(!s->nosplit) { + ctxt->cursym = s; ch.sym = s; - ch.limit = StackLimit - CallSize; stkcheck(&ch, 0); } } +} static int stkcheck(Chain *up, int depth) { Chain ch, ch1; - Prog *p; - Sym *s; - int limit, prolog; + LSym *s; + int limit; + Reloc *r, *endr; + Pciter pcsp; limit = up->limit; s = up->sym; - p = s->text; - // Small optimization: don't repeat work at top. - if(s->stkcheck && limit == StackLimit-CallSize) + // Don't duplicate work: only need to consider each + // function at top of safe zone once. + if(limit == StackLimit-callsize()) { + if(s->stkcheck) return 0; + s->stkcheck = 1; + } if(depth > 100) { diag("nosplit stack check too deep"); @@ -1728,11 +1104,11 @@ stkcheck(Chain *up, int depth) return -1; } - if(p == nil || p->link == nil) { + if(s->external || s->pcln == nil) { // external function. // should never be called directly. // only diagnose the direct caller. - if(depth == 1) + if(depth == 1 && s->type != SXREF) diag("call to external function %s", s->name); return -1; } @@ -1748,50 +1124,56 @@ stkcheck(Chain *up, int depth) return 0; ch.up = up; - prolog = (s->text->textflag & NOSPLIT) == 0; - for(p = s->text; p != P; p = p->link) { - limit -= p->spadj; - if(prolog && p->spadj != 0) { - // The first stack adjustment in a function with a - // split-checking prologue marks the end of the - // prologue. Assuming the split check is correct, - // after the adjustment there should still be at least - // StackLimit bytes available below the stack pointer. - // If this is not the top call in the chain, no need - // to duplicate effort, so just stop. - if(depth > 0) - return 0; - prolog = 0; - limit = StackLimit; - } - if(limit < 0) { - stkbroke(up, limit); + + // Walk through sp adjustments in function, consuming relocs. + r = s->r; + endr = r + s->nr; + for(pciterinit(ctxt, &pcsp, &s->pcln->pcsp); !pcsp.done; pciternext(&pcsp)) { + // pcsp.value is in effect for [pcsp.pc, pcsp.nextpc). + + // Check stack size in effect for this span. + if(limit - pcsp.value < 0) { + stkbroke(up, limit - pcsp.value); return -1; } - if(iscall(p)) { - limit -= CallSize; - ch.limit = limit; - if(p->to.type == D_BRANCH) { + + // Process calls in this span. + for(; r < endr && r->off < pcsp.nextpc; r++) { + switch(r->type) { + case R_CALL: + case R_CALLARM: // Direct call. - ch.sym = p->to.sym; + ch.limit = limit - pcsp.value - callsize(); + ch.sym = r->sym; if(stkcheck(&ch, depth+1) < 0) return -1; - } else { - // Indirect call. Assume it is a splitting function, + + // If this is a call to morestack, we've just raised our limit back + // to StackLimit beyond the frame size. + if(strncmp(r->sym->name, "runtime.morestack", 17) == 0) { + limit = StackLimit + s->locals; + if(thechar == '5') + limit += 4; // saved LR + } + break; + + case R_CALLIND: + // Indirect call. Assume it is a call to a splitting function, // so we have to make sure it can call morestack. - limit -= CallSize; + // Arrange the data structures to report both calls, so that + // if there is an error, stkprint shows all the steps involved. + ch.limit = limit - pcsp.value - callsize(); ch.sym = nil; - ch1.limit = limit; + ch1.limit = ch.limit - callsize(); // for morestack in called prologue ch1.up = &ch; ch1.sym = morestack; if(stkcheck(&ch1, depth+2) < 0) return -1; - limit += CallSize; + break; } - limit += CallSize; + } } - } return 0; } @@ -1814,7 +1196,7 @@ stkprint(Chain *ch, int limit) if(ch->up == nil) { // top of chain. ch->sym != nil. - if(ch->sym->text->textflag & NOSPLIT) + if(ch->sym->nosplit) print("\t%d\tassumed on entry to %s\n", ch->limit, name); else print("\t%d\tguaranteed after split check in %s\n", ch->limit, name); @@ -1827,53 +1209,15 @@ stkprint(Chain *ch, int limit) print("\t%d\tafter %s uses %d\n", limit, name, ch->limit - limit); } -int -headtype(char *name) -{ - int i; - - for(i=0; headers[i].name; i++) - if(strcmp(name, headers[i].name) == 0) { - headstring = headers[i].name; - return headers[i].val; - } - fprint(2, "unknown header type -H %s\n", name); - errorexit(); - return -1; // not reached -} - -char* -headstr(int v) -{ - static char buf[20]; - int i; - - for(i=0; headers[i].name; i++) - if(v == headers[i].val) - return headers[i].name; - snprint(buf, sizeof buf, "%d", v); - return buf; -} - -void -undef(void) -{ - Sym *s; - - for(s = allsym; s != S; s = s->allsym) - if(s->type == SXREF) - diag("%s(%d): not defined", s->name, s->version); -} - int Yconv(Fmt *fp) { - Sym *s; + LSym *s; Fmt fmt; int i; char *str; - s = va_arg(fp->args, Sym*); + s = va_arg(fp->args, LSym*); if (s == S) { fmtprint(fp, ""); } else { @@ -1967,6 +1311,14 @@ usage(void) void setheadtype(char *s) { + int h; + + h = headtype(s); + if(h < 0) { + fprint(2, "unknown header type -H %s\n", s); + errorexit(); + } + headstring = s; HEADTYPE = headtype(s); } @@ -1985,22 +1337,22 @@ doversion(void) } void -genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)) +genasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*)) { Auto *a; - Sym *s; + LSym *s; int32 off; // These symbols won't show up in the first loop below because we // skip STEXT symbols. Normal STEXT symbols are emitted by walking textp. - s = lookup("text", 0); + s = linklookup(ctxt, "text", 0); if(s->type == STEXT) put(s, s->name, 'T', s->value, s->size, s->version, 0); - s = lookup("etext", 0); + s = linklookup(ctxt, "etext", 0); if(s->type == STEXT) put(s, s->name, 'T', s->value, s->size, s->version, 0); - for(s=allsym; s!=S; s=s->allsym) { + for(s=ctxt->allsym; s!=S; s=s->allsym) { if(s->hide || (s->name[0] == '.' && s->version == 0 && strcmp(s->name, ".rathole") != 0)) continue; switch(s->type&SMASK) { @@ -2036,20 +1388,20 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)) } } - for(s = textp; s != nil; s = s->next) { - if(s->text == nil) - continue; - + for(s = ctxt->textp; s != nil; s = s->next) { put(s, s->name, 'T', s->value, s->size, s->version, s->gotype); + // NOTE(ality): acid can't produce a stack trace without .frame symbols + put(nil, ".frame", 'm', s->locals+PtrSize, 0, 0, 0); + for(a=s->autom; a; a=a->link) { // Emit a or p according to actual offset, even if label is wrong. // This avoids negative offsets, which cannot be encoded. - if(a->type != D_AUTO && a->type != D_PARAM) + if(a->type != A_AUTO && a->type != A_PARAM) continue; // compute offset relative to FP - if(a->type == D_PARAM) + if(a->type == A_PARAM) off = a->aoffset; else off = a->aoffset - PtrSize; @@ -2075,461 +1427,126 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)) Bflush(&bso); } -char* -estrdup(char *p) -{ - p = strdup(p); - if(p == nil) { - cursym = S; - diag("out of memory"); - errorexit(); - } - return p; -} - -void* -erealloc(void *p, long n) +vlong +symaddr(LSym *s) { - p = realloc(p, n); - if(p == nil) { - cursym = S; - diag("out of memory"); - errorexit(); - } - return p; + if(!s->reachable) + diag("unreachable symbol in symaddr - %s", s->name); + return s->value; } -// Saved history stacks encountered while reading archives. -// Keeping them allows us to answer virtual lineno -> file:line -// queries. -// -// The history stack is a complex data structure, described best at the -// bottom of http://plan9.bell-labs.com/magic/man2html/6/a.out. -// One of the key benefits of interpreting it here is that the runtime -// does not have to. Perhaps some day the compilers could generate -// a simpler linker input too. - -struct Hist -{ - int32 line; - int32 off; - Sym *file; -}; - -static Hist *histcopy; -static Hist *hist; -static int32 nhist; -static int32 maxhist; -static int32 histdepth; -static int32 nhistfile; -static Sym *filesyms; - -// savehist processes a single line, off history directive -// found in the input object file. void -savehist(int32 line, int32 off) +xdefine(char *p, int t, vlong v) { - char tmp[1024]; - Sym *file; - Hist *h; - - // NOTE(rsc): We used to do the copyhistfrog first and this - // condition was if(tmp[0] != '\0') to check for an empty string, - // implying that histfrogp == 0, implying that this is a history pop. - // However, on Windows in the misc/cgo test, the linker is - // presented with an ANAME corresponding to an empty string, - // that ANAME ends up being the only histfrog, and thus we have - // a situation where histfrogp > 0 (not a pop) but the path we find - // is the empty string. Really that shouldn't happen, but it doesn't - // seem to be bothering anyone yet, and it's easier to fix the condition - // to test histfrogp than to track down where that empty string is - // coming from. Probably it is coming from go tool pack's P command. - if(histfrogp > 0) { - tmp[0] = '\0'; - copyhistfrog(tmp, sizeof tmp); - file = lookup(tmp, HistVersion); - if(file->type != SFILEPATH) { - file->value = ++nhistfile; - file->type = SFILEPATH; - file->next = filesyms; - filesyms = file; - } - } else - file = nil; + LSym *s; - if(file != nil && line == 1 && off == 0) { - // start of new stack - if(histdepth != 0) { - diag("history stack phase error: unexpected start of new stack depth=%d file=%s", histdepth, tmp); - errorexit(); - } - nhist = 0; - histcopy = nil; - } - - if(nhist >= maxhist) { - if(maxhist == 0) - maxhist = 1; - maxhist *= 2; - hist = erealloc(hist, maxhist*sizeof hist[0]); - } - h = &hist[nhist++]; - h->line = line; - h->off = off; - h->file = file; - - if(file != nil) { - if(off == 0) - histdepth++; - } else { - if(off != 0) { - diag("history stack phase error: bad offset in pop"); - errorexit(); - } - histdepth--; - } + s = linklookup(ctxt, p, 0); + s->type = t; + s->value = v; + s->reachable = 1; + s->special = 1; } -// gethist returns the history stack currently in effect. -// The result is valid indefinitely. -Hist* -gethist(void) +vlong +datoff(vlong addr) { - if(histcopy == nil) { - if(nhist == 0) - return nil; - histcopy = mal((nhist+1)*sizeof hist[0]); - memmove(histcopy, hist, nhist*sizeof hist[0]); - histcopy[nhist].line = -1; - } - return histcopy; + 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; } -typedef struct Hstack Hstack; -struct Hstack -{ - Hist *h; - int delta; -}; - -// getline sets *f to the file number and *l to the line number -// of the virtual line number line according to the history stack h. -void -getline(Hist *h, int32 line, int32 *f, int32 *l) +vlong +entryvalue(void) { - Hstack stk[100]; - int nstk, start; - Hist *top, *h0; - static Hist *lasth; - static int32 laststart, lastend, lastdelta, lastfile; - - h0 = h; - *f = 0; - *l = 0; - start = 0; - if(h == nil || line == 0) { - print("%s: getline: h=%p line=%d\n", cursym->name, h, line); - return; - } - - // Cache span used during last lookup, so that sequential - // translation of line numbers in compiled code is efficient. - if(!debug['O'] && lasth == h && laststart <= line && line < lastend) { - *f = lastfile; - *l = line - lastdelta; - return; - } - - if(debug['O']) - print("getline %d laststart=%d lastend=%d\n", line, laststart, lastend); - - nstk = 0; - for(; h->line != -1; h++) { - if(debug['O']) - print("\t%s %d %d\n", h->file ? h->file->name : "?", h->line, h->off); - - if(h->line > line) { - if(nstk == 0) { - diag("history stack phase error: empty stack at line %d", (int)line); - errorexit(); - } - top = stk[nstk-1].h; - lasth = h; - lastfile = top->file->value; - laststart = start; - lastend = h->line; - lastdelta = stk[nstk-1].delta; - *f = lastfile; - *l = line - lastdelta; - if(debug['O']) - print("\tgot %d %d [%d %d %d]\n", *f, *l, laststart, lastend, lastdelta); - return; - } - if(h->file == nil) { - // pop included file - if(nstk == 0) { - diag("history stack phase error: stack underflow"); - errorexit(); - } - nstk--; - if(nstk > 0) - stk[nstk-1].delta += h->line - stk[nstk].h->line; - start = h->line; - } else if(h->off == 0) { - // push included file - if(nstk >= nelem(stk)) { - diag("history stack phase error: stack overflow"); - errorexit(); - } - start = h->line; - stk[nstk].h = h; - stk[nstk].delta = h->line - 1; - nstk++; - } else { - // #line directive - if(nstk == 0) { - diag("history stack phase error: stack underflow"); - errorexit(); - } - stk[nstk-1].h = h; - stk[nstk-1].delta = h->line - h->off; - start = h->line; - } - if(debug['O']) - print("\t\tnstk=%d delta=%d\n", nstk, stk[nstk].delta); - } + char *a; + LSym *s; - diag("history stack phase error: cannot find line for %d", line); - nstk = 0; - for(h = h0; h->line != -1; h++) { - print("\t%d %d %s\n", h->line, h->off, h->file ? h->file->name : ""); - if(h->file == nil) - nstk--; - else if(h->off == 0) - nstk++; - } + a = INITENTRY; + if(*a >= '0' && *a <= '9') + return atolwhex(a); + s = linklookup(ctxt, a, 0); + if(s->type == 0) + return INITTEXT; + if(s->type != STEXT) + diag("entry not text: %s", s->name); + return s->value; } -// defgostring returns a symbol for the Go string containing text. -Sym* -defgostring(char *text) +static void +undefsym(LSym *s) { - char *p; - Sym *s; - int32 n; - - n = strlen(text); - p = smprint("go.string.\"%Z\"", text); - s = lookup(p, 0); - if(s->size == 0) { - s->type = SGOSTRING; - s->reachable = 1; - s->size = 2*PtrSize+n; - symgrow(s, 2*PtrSize+n); - setaddrplus(s, 0, s, 2*PtrSize); - setuintxx(s, PtrSize, n, PtrSize); - memmove(s->p+2*PtrSize, text, n); - } - s->reachable = 1; - return s; -} + int i; + Reloc *r; -// addpctab appends to f a pc-value table, storing its offset at off. -// The pc-value table is for func and reports the value of valfunc -// parameterized by arg. -static int32 -addpctab(Sym *f, int32 off, Sym *func, char *desc, int32 (*valfunc)(Sym*, int32, Prog*, int32, int32), int32 arg) -{ - int32 start; - - start = f->np; - funcpctab(f, func, desc, valfunc, arg); - if(start == f->np) { - // no table - return setuint32(f, off, 0); - } - if((int32)start > (int32)f->np) { - diag("overflow adding pc-table: symbol too large"); - errorexit(); + ctxt->cursym = s; + for(i=0; inr; i++) { + r = &s->r[i]; + if(r->sym == nil) // happens for some external ARM relocs + continue; + if(r->sym->type == Sxxx || r->sym->type == SXREF) + diag("undefined: %s", r->sym->name); + if(!r->sym->reachable) + diag("use of unreachable symbol: %s", r->sym->name); } - return setuint32(f, off, start); } -static int32 -ftabaddstring(Sym *ftab, char *s) +void +undef(void) { - int32 n, start; + LSym *s; - n = strlen(s)+1; - start = ftab->np; - symgrow(ftab, start+n+1); - strcpy((char*)ftab->p + start, s); - return start; + for(s = ctxt->textp; s != nil; s = s->next) + undefsym(s); + for(s = datap; s != nil; s = s->next) + undefsym(s); + if(nerrors > 0) + errorexit(); } -// pclntab initializes the pclntab symbol with -// runtime function and file name information. void -pclntab(void) +callgraph(void) { - Prog *p; - int32 i, n, nfunc, start, funcstart; - uint32 *havepc, *havefunc; - Sym *ftab, *s; - int32 npcdata, nfuncdata, off, end; - int64 funcdata_bytes; - - funcdata_bytes = 0; - ftab = lookup("pclntab", 0); - ftab->type = SPCLNTAB; - ftab->reachable = 1; - - // See golang.org/s/go12symtab for the format. Briefly: - // 8-byte header - // nfunc [PtrSize bytes] - // function table, alternating PC and offset to func struct [each entry PtrSize bytes] - // end PC [PtrSize bytes] - // offset to file table [4 bytes] - nfunc = 0; - for(cursym = textp; cursym != nil; cursym = cursym->next) - nfunc++; - symgrow(ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize+4); - setuint32(ftab, 0, 0xfffffffb); - setuint8(ftab, 6, MINLC); - setuint8(ftab, 7, PtrSize); - setuintxx(ftab, 8, nfunc, PtrSize); - - nfunc = 0; - for(cursym = textp; cursym != nil; cursym = cursym->next, nfunc++) { - funcstart = ftab->np; - funcstart += -ftab->np & (PtrSize-1); - - setaddr(ftab, 8+PtrSize+nfunc*2*PtrSize, cursym); - setuintxx(ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize, funcstart, PtrSize); - - npcdata = 0; - nfuncdata = 0; - for(p = cursym->text; p != P; p = p->link) { - if(p->as == APCDATA && p->from.offset >= npcdata) - npcdata = p->from.offset+1; - if(p->as == AFUNCDATA && p->from.offset >= nfuncdata) - nfuncdata = p->from.offset+1; - } - - // fixed size of struct, checked below - off = funcstart; - end = funcstart + PtrSize + 3*4 + 5*4 + npcdata*4 + nfuncdata*PtrSize; - if(nfuncdata > 0 && (end&(PtrSize-1))) - end += 4; - symgrow(ftab, end); - - // entry uintptr - off = setaddr(ftab, off, cursym); - - // name int32 - off = setuint32(ftab, off, ftabaddstring(ftab, cursym->name)); - - // args int32 - // TODO: Move into funcinfo. - if(cursym->text == nil) - off = setuint32(ftab, off, ArgsSizeUnknown); - else - off = setuint32(ftab, off, cursym->args); - - // frame int32 - // TODO: Remove entirely. The pcsp table is more precise. - // This is only used by a fallback case during stack walking - // when a called function doesn't have argument information. - // We need to make sure everything has argument information - // and then remove this. - if(cursym->text == nil) - off = setuint32(ftab, off, 0); - else - off = setuint32(ftab, off, (uint32)cursym->text->to.offset+PtrSize); - - // pcsp table (offset int32) - off = addpctab(ftab, off, cursym, "pctospadj", pctospadj, 0); - - // pcfile table (offset int32) - off = addpctab(ftab, off, cursym, "pctofileline file", pctofileline, 0); + LSym *s; + Reloc *r; + int i; - // pcln table (offset int32) - off = addpctab(ftab, off, cursym, "pctofileline line", pctofileline, 1); - - // npcdata int32 - off = setuint32(ftab, off, npcdata); - - // nfuncdata int32 - off = setuint32(ftab, off, nfuncdata); - - // tabulate which pc and func data we have. - n = ((npcdata+31)/32 + (nfuncdata+31)/32)*4; - havepc = mal(n); - havefunc = havepc + (npcdata+31)/32; - for(p = cursym->text; p != P; p = p->link) { - if(p->as == AFUNCDATA) { - if((havefunc[p->from.offset/32]>>(p->from.offset%32))&1) - diag("multiple definitions for FUNCDATA $%d", p->from.offset); - havefunc[p->from.offset/32] |= 1<<(p->from.offset%32); - } - if(p->as == APCDATA) - havepc[p->from.offset/32] |= 1<<(p->from.offset%32); - } + if(!debug['c']) + return; - // pcdata. - for(i=0; i>(i%32))&1) { - off = setuint32(ftab, off, 0); + for(s = ctxt->textp; s != nil; s = s->next) { + for(i=0; inr; i++) { + r = &s->r[i]; + if(r->sym == nil) continue; - } - off = addpctab(ftab, off, cursym, "pctopcdata", pctopcdata, i); - } - - unmal(havepc, n); - - // funcdata, must be pointer-aligned and we're only int32-aligned. - // Unlike pcdata, can gather in a single pass. - // Missing funcdata will be 0 (nil pointer). - if(nfuncdata > 0) { - if(off&(PtrSize-1)) - off += 4; - for(p = cursym->text; p != P; p = p->link) { - if(p->as == AFUNCDATA) { - i = p->from.offset; - if(p->to.type == D_CONST) - setuintxx(ftab, off+PtrSize*i, p->to.offset, PtrSize); - else { - // TODO: Dedup. - funcdata_bytes += p->to.sym->size; - setaddrplus(ftab, off+PtrSize*i, p->to.sym, p->to.offset); - } - } - } - off += nfuncdata*PtrSize; - } - - if(off != end) { - diag("bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d)", funcstart, off, end, npcdata, nfuncdata); - errorexit(); + if((r->type == R_CALL || r->type == R_CALLARM) && r->sym->type == STEXT) + Bprint(&bso, "%s calls %s\n", s->name, r->sym->name); } - - // Final entry of table is just end pc. - if(cursym->next == nil) - setaddrplus(ftab, 8+PtrSize+(nfunc+1)*2*PtrSize, cursym, cursym->size); } - - // Start file table. - start = ftab->np; - start += -ftab->np & (PtrSize-1); - setuint32(ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize, start); +} - symgrow(ftab, start+(nhistfile+1)*4); - setuint32(ftab, start, nhistfile); - for(s = filesyms; s != S; s = s->next) - setuint32(ftab, start + s->value*4, ftabaddstring(ftab, s->name)); +void +diag(char *fmt, ...) +{ + char buf[1024], *tn, *sep; + va_list arg; - ftab->size = ftab->np; - - if(debug['v']) - Bprint(&bso, "%5.2f pclntab=%lld bytes, funcdata total %lld bytes\n", cputime(), (vlong)ftab->size, (vlong)funcdata_bytes); -} + tn = ""; + sep = ""; + if(ctxt->cursym != S) { + tn = ctxt->cursym->name; + sep = ": "; + } + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + print("%s%s%s\n", tn, sep, buf); + + nerrors++; + if(nerrors > 20) { + print("too many errors\n"); + errorexit(); + } +} diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h index be95bb46e..7267c6371 100644 --- a/src/cmd/ld/lib.h +++ b/src/cmd/ld/lib.h @@ -28,68 +28,6 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -enum -{ - Sxxx, - - /* order here is order in output file */ - /* readonly, executable */ - STEXT, - SELFRXSECT, - - /* readonly, non-executable */ - STYPE, - SSTRING, - SGOSTRING, - SGOFUNC, - SRODATA, - SFUNCTAB, - STYPELINK, - SSYMTAB, // TODO: move to unmapped section - SPCLNTAB, - SELFROSECT, - - /* writable, non-executable */ - SMACHOPLT, - SELFSECT, - SMACHO, /* Mach-O __nl_symbol_ptr */ - SMACHOGOT, - SNOPTRDATA, - SINITARR, - SDATA, - SWINDOWS, - SBSS, - SNOPTRBSS, - STLSBSS, - - /* not mapped */ - SXREF, - SMACHOSYMSTR, - SMACHOSYMTAB, - SMACHOINDIRECTPLT, - SMACHOINDIRECTGOT, - SFILE, - SFILEPATH, - SCONST, - SDYNIMPORT, - SHOSTOBJ, - - SSUB = 1<<8, /* sub-symbol, linked from parent via ->sub list */ - SMASK = SSUB - 1, - SHIDDEN = 1<<9, // hidden or local symbol - - NHASH = 100003, -}; - -typedef struct Library Library; -struct Library -{ - char *objref; // object where we found the reference - char *srcref; // src file where we found the reference - char *file; // object file - 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 @@ -125,39 +63,18 @@ struct Section uvlong rellen; }; -typedef struct Hist Hist; - -#pragma incomplete struct Hist - extern char symname[]; -extern char **libdir; -extern int nlibdir; -extern int version; EXTERN char* INITENTRY; -EXTERN char* thestring; -EXTERN Library* library; -EXTERN int libraryp; -EXTERN int nlibrary; -EXTERN Sym* hash[NHASH]; -EXTERN Sym* allsym; -EXTERN Sym* histfrog[MAXHIST]; -EXTERN uchar fnuxi8[8]; -EXTERN uchar fnuxi4[4]; -EXTERN int histfrogp; -EXTERN int histgen; -EXTERN uchar inuxi1[1]; -EXTERN uchar inuxi2[2]; -EXTERN uchar inuxi4[4]; -EXTERN uchar inuxi8[8]; +extern char* thestring; +extern LinkArch* thelinkarch; EXTERN char* outfile; -EXTERN int32 nsymbol; -EXTERN char* thestring; EXTERN int ndynexp; -EXTERN Sym** dynexp; +EXTERN LSym** dynexp; EXTERN int nldflag; EXTERN char** ldflag; EXTERN int havedynamic; +EXTERN int funcalign; EXTERN int iscgo; EXTERN int elfglobalsymndx; EXTERN char* flag_installsuffix; @@ -169,16 +86,21 @@ EXTERN char* tmpdir; EXTERN char* extld; EXTERN char* extldflags; EXTERN int debug_s; // backup old value of debug['s'] +EXTERN Link* ctxt; +EXTERN int32 HEADR; +EXTERN int32 HEADTYPE; +EXTERN int32 INITRND; +EXTERN int64 INITTEXT; +EXTERN int64 INITDAT; +EXTERN char* INITENTRY; /* entry point */ +EXTERN char* noname; +EXTERN char* paramspace; +EXTERN int nerrors; -enum -{ - LinkAuto = 0, - LinkInternal, - LinkExternal, -}; EXTERN int linkmode; +EXTERN int64 liveness; -// for dynexport field of Sym +// for dynexport field of LSym enum { CgoExportDynamic = 1<<0, @@ -190,119 +112,6 @@ EXTERN Segment segrodata; EXTERN Segment segdata; EXTERN Segment segdwarf; -void setlinkmode(char*); -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 savehist(int32 line, int32 off); -Hist* gethist(void); -void getline(Hist*, int32 line, int32 *f, int32 *l); -void asmlc(void); -void histtoauto(void); -void collapsefrog(Sym *s); -Sym* newsym(char *symb, int v); -Sym* lookup(char *symb, int v); -Sym* rlookup(char *symb, int v); -void nuxiinit(void); -int find1(int32 l, int c); -int find2(int32 l, int c); -int32 ieeedtof(Ieee *e); -double ieeedtod(Ieee *e); -void undefsym(Sym *s); -void zerosig(char *sp); -void readundefs(char *f, int t); -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 adddynrela(Sym*, Sym*, Reloc*); -void ldobj1(Biobuf *f, char*, int64 len, char *pn); -void ldobj(Biobuf*, char*, int64, char*, char*, int); -void ldelf(Biobuf*, char*, int64, char*); -void ldmacho(Biobuf*, char*, int64, char*); -void ldpe(Biobuf*, char*, int64, char*); -void ldpkg(Biobuf*, char*, int64, char*, int); -void mark(Sym *s); -void mkfwd(void); -char* expandpkg(char*, char*); -void deadcode(void); -Reloc* addrel(Sym*); -void codeblk(int32, int32); -void datblk(int32, int32); -void reloc(void); -void relocsym(Sym*); -void savedata(Sym*, Prog*, char*); -void symgrow(Sym*, int32); -void addstrdata(char*, char*); -vlong addstring(Sym*, char*); -vlong adduint8(Sym*, uint8); -vlong adduint16(Sym*, uint16); -vlong adduint32(Sym*, uint32); -vlong adduint64(Sym*, uint64); -vlong adduintxx(Sym*, uint64, int); -vlong addaddr(Sym*, Sym*); -vlong addaddrplus(Sym*, Sym*, vlong); -vlong addpcrelplus(Sym*, Sym*, vlong); -vlong addsize(Sym*, Sym*); -vlong setaddrplus(Sym*, vlong, Sym*, vlong); -vlong setaddr(Sym*, vlong, Sym*); -vlong setuint8(Sym*, vlong, uint8); -vlong setuint16(Sym*, vlong, uint16); -vlong setuint32(Sym*, vlong, uint32); -vlong setuint64(Sym*, vlong, uint64); -vlong setuintxx(Sym*, vlong, uint64, vlong); -void asmsym(void); -void asmelfsym(void); -void asmplan9sym(void); -void putelfsectionsym(Sym*, int); -void putelfsymshndx(vlong, int); -void strnput(char*, int); -void dodata(void); -void dosymtype(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); -void dostkcheck(void); -void undef(void); -void doweak(void); -void setpersrc(Sym*); -void doversion(void); -void usage(void); -void setinterp(char*); -Sym* listsort(Sym*, int(*cmp)(Sym*, Sym*), int); -int valuecmp(Sym*, Sym*); -void hostobjs(void); -void hostlink(void); -char* estrdup(char*); -void* erealloc(void*, long); -Sym* defgostring(char*); - -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 { @@ -325,28 +134,6 @@ enum { Pkgdef }; -/* executable header types */ -enum { - Hgarbunix = 0, // garbage unix - Hnoheader, // no header - Hunixcoff, // unix coff - Hrisc, // aif for risc os - Hplan9x32, // plan 9 32-bit format - Hplan9x64, // plan 9 64-bit format - Hmsdoscom, // MS-DOS .COM - Hnetbsd, // NetBSD - Hmsdosexe, // fake MS-DOS .EXE - Hixp1200, // IXP1200 (raw) - Helf, // ELF32 - Hipaq, // ipaq - Hdarwin, // Apple Mach-O - Hlinux, // Linux ELF - Hfreebsd, // FreeBSD ELF - Hwindows, // MS Windows PE - Hopenbsd, // OpenBSD ELF - Hdragonfly, // DragonFly ELF -}; - typedef struct Header Header; struct Header { char *name; @@ -356,14 +143,9 @@ struct Header { EXTERN char* headstring; extern Header headers[]; -int headtype(char*); -char* headstr(int); -void setheadtype(char*); - -int Yconv(Fmt*); - -#pragma varargck type "O" int -#pragma varargck type "Y" Sym* +#pragma varargck type "Y" LSym* +#pragma varargck type "Z" char* +#pragma varargck type "i" char* // buffered output @@ -383,29 +165,117 @@ EXTERN char* cbpmax; if(--cbc <= 0)\ cflush(); } +void Lflag(char *arg); +int Yconv(Fmt *fp); +int Zconv(Fmt *fp); +void addexport(void); +void address(void); +Section*addsection(Segment *seg, char *name, int rwx); +void addstrdata(char *name, char *value); +vlong addstring(LSym *s, char *str); +void asmelfsym(void); +void asmplan9sym(void); +uint16 be16(uchar *b); +uint32 be32(uchar *b); +uint64 be64(uchar *b); +void callgraph(void); void cflush(void); +void codeblk(int32 addr, int32 size); vlong cpos(void); -void cseek(vlong); -void cwrite(void*, int); +void cseek(vlong p); +void cwrite(void *buf, int n); +void datblk(int32 addr, int32 size); +int datcmp(LSym *s1, LSym *s2); +vlong datoff(vlong addr); +void deadcode(void); +LSym* decodetype_arrayelem(LSym *s); +vlong decodetype_arraylen(LSym *s); +LSym* decodetype_chanelem(LSym *s); +int decodetype_funcdotdotdot(LSym *s); +int decodetype_funcincount(LSym *s); +LSym* decodetype_funcintype(LSym *s, int i); +int decodetype_funcoutcount(LSym *s); +LSym* decodetype_funcouttype(LSym *s, int i); +LSym* decodetype_gc(LSym *s); +vlong decodetype_ifacemethodcount(LSym *s); +uint8 decodetype_kind(LSym *s); +LSym* decodetype_mapkey(LSym *s); +LSym* decodetype_mapvalue(LSym *s); +LSym* decodetype_ptrelem(LSym *s); +vlong decodetype_size(LSym *s); +int decodetype_structfieldcount(LSym *s); +char* decodetype_structfieldname(LSym *s, int i); +vlong decodetype_structfieldoffs(LSym *s, int i); +LSym* decodetype_structfieldtype(LSym *s, int i); +void dodata(void); +void dostkcheck(void); +void dostkoff(void); +void dosymtype(void); +void doversion(void); +void doweak(void); +void dynreloc(void); +void dynrelocsym(LSym *s); +vlong entryvalue(void); +void errorexit(void); +void follow(void); +void genasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*)); +void growdatsize(vlong *datsizep, LSym *s); +char* headstr(int v); +int headtype(char *name); +void hostlink(void); +void hostobjs(void); +int iconv(Fmt *fp); void importcycles(void); -int Zconv(Fmt*); +void linkarchinit(void); +void ldelf(Biobuf *f, char *pkg, int64 len, char *pn); +void ldhostobj(void (*ld)(Biobuf*, char*, int64, char*), Biobuf *f, char *pkg, int64 len, char *pn, char *file); +void ldmacho(Biobuf *f, char *pkg, int64 len, char *pn); +void ldobj(Biobuf *f, char *pkg, int64 len, char *pn, char *file, int whence); +void ldpe(Biobuf *f, char *pkg, int64 len, char *pn); +void ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence); +uint16 le16(uchar *b); +uint32 le32(uchar *b); +uint64 le64(uchar *b); +void libinit(void); +LSym* listsort(LSym *l, int (*cmp)(LSym*, LSym*), int off); +void loadinternal(char *name); +void loadlib(void); +void lputb(int32 l); +void lputl(int32 l); +void* mal(uint32 n); +void mark(LSym *s); +void mywhatsys(void); +struct ar_hdr; +void objfile(char *file, char *pkg); +void patch(void); +int pathchar(void); +void pcln(void); +void pclntab(void); +void putelfsectionsym(LSym* s, int shndx); +void putelfsymshndx(vlong sympos, int shndx); +void putsymb(LSym *s, char *name, int t, vlong v, vlong size, int ver, LSym *typ); +int rbyoff(const void *va, const void *vb); +void reloc(void); +void relocsym(LSym *s); +void setheadtype(char *s); +void setinterp(char *s); +void setlinkmode(char *arg); +void span(void); +void strnput(char *s, int n); +vlong symaddr(LSym *s); +void symtab(void); +void textaddress(void); +void undef(void); +void unmal(void *v, uint32 n); +void usage(void); +void vputb(uint64 v); +int valuecmp(LSym *a, LSym *b); +void vputl(uint64 v); +void wputb(ushort w); +void wputl(ushort w); +void xdefine(char *p, int t, vlong v); +void zerosig(char *sp); +void archinit(void); +void diag(char *fmt, ...); -uint8 decodetype_kind(Sym*); -vlong decodetype_size(Sym*); -Sym* decodetype_gc(Sym*); -Sym* decodetype_arrayelem(Sym*); -vlong decodetype_arraylen(Sym*); -Sym* decodetype_ptrelem(Sym*); -Sym* decodetype_mapkey(Sym*); -Sym* decodetype_mapvalue(Sym*); -Sym* decodetype_chanelem(Sym*); -int decodetype_funcdotdotdot(Sym*); -int decodetype_funcincount(Sym*); -int decodetype_funcoutcount(Sym*); -Sym* decodetype_funcintype(Sym*, int); -Sym* decodetype_funcouttype(Sym*, int); -int decodetype_structfieldcount(Sym*); -char* decodetype_structfieldname(Sym*, int); -Sym* decodetype_structfieldtype(Sym*, int); -vlong decodetype_structfieldoffs(Sym*, int); -vlong decodetype_ifacemethodcount(Sym*); +#pragma varargck argpos diag 1 diff --git a/src/cmd/ld/macho.c b/src/cmd/ld/macho.c index d135a92da..61306bb7c 100644 --- a/src/cmd/ld/macho.c +++ b/src/cmd/ld/macho.c @@ -25,7 +25,7 @@ enum }; static int nkind[NumSymKind]; -static Sym** sortsym; +static LSym** sortsym; static int nsortsym; // Amount of space left for adding load commands @@ -232,37 +232,37 @@ machowrite(void) void domacho(void) { - Sym *s; + LSym *s; if(debug['d']) return; // empirically, string table must begin with " \x00". - s = lookup(".machosymstr", 0); + s = linklookup(ctxt, ".machosymstr", 0); s->type = SMACHOSYMSTR; s->reachable = 1; - adduint8(s, ' '); - adduint8(s, '\0'); + adduint8(ctxt, s, ' '); + adduint8(ctxt, s, '\0'); - s = lookup(".machosymtab", 0); + s = linklookup(ctxt, ".machosymtab", 0); s->type = SMACHOSYMTAB; s->reachable = 1; if(linkmode != LinkExternal) { - s = lookup(".plt", 0); // will be __symbol_stub + s = linklookup(ctxt, ".plt", 0); // will be __symbol_stub s->type = SMACHOPLT; s->reachable = 1; - s = lookup(".got", 0); // will be __nl_symbol_ptr + s = linklookup(ctxt, ".got", 0); // will be __nl_symbol_ptr s->type = SMACHOGOT; s->reachable = 1; s->align = 4; - s = lookup(".linkedit.plt", 0); // indirect table for .plt + s = linklookup(ctxt, ".linkedit.plt", 0); // indirect table for .plt s->type = SMACHOINDIRECTPLT; s->reachable = 1; - s = lookup(".linkedit.got", 0); // indirect table for .got + s = linklookup(ctxt, ".linkedit.got", 0); // indirect table for .got s->type = SMACHOINDIRECTGOT; s->reachable = 1; } @@ -334,7 +334,7 @@ machoshbits(MachoSeg *mseg, Section *sect, char *segname) if(strcmp(sect->name, ".got") == 0) { msect->name = "__nl_symbol_ptr"; msect->flag = 6; /* section with nonlazy symbol pointers */ - msect->res1 = lookup(".linkedit.plt", 0)->size / 4; /* offset into indirect symbol table */ + msect->res1 = linklookup(ctxt, ".linkedit.plt", 0)->size / 4; /* offset into indirect symbol table */ } } @@ -432,13 +432,13 @@ asmbmacho(void) } if(!debug['d']) { - Sym *s1, *s2, *s3, *s4; + LSym *s1, *s2, *s3, *s4; // must match domacholink below - s1 = lookup(".machosymtab", 0); - s2 = lookup(".linkedit.plt", 0); - s3 = lookup(".linkedit.got", 0); - s4 = lookup(".machosymstr", 0); + s1 = linklookup(ctxt, ".machosymtab", 0); + s2 = linklookup(ctxt, ".linkedit.plt", 0); + s3 = linklookup(ctxt, ".linkedit.got", 0); + s4 = linklookup(ctxt, ".machosymstr", 0); if(linkmode != LinkExternal) { ms = newMachoSeg("__LINKEDIT", 0); @@ -484,7 +484,7 @@ asmbmacho(void) } static int -symkind(Sym *s) +symkind(LSym *s) { if(s->type == SDYNIMPORT) return SymKindUndef; @@ -494,7 +494,7 @@ symkind(Sym *s) } static void -addsym(Sym *s, char *name, int type, vlong addr, vlong size, int ver, Sym *gotype) +addsym(LSym *s, char *name, int type, vlong addr, vlong size, int ver, LSym *gotype) { USED(name); USED(addr); @@ -524,11 +524,11 @@ addsym(Sym *s, char *name, int type, vlong addr, vlong size, int ver, Sym *gotyp static int scmp(const void *p1, const void *p2) { - Sym *s1, *s2; + LSym *s1, *s2; int k1, k2; - s1 = *(Sym**)p1; - s2 = *(Sym**)p2; + s1 = *(LSym**)p1; + s2 = *(LSym**)p2; k1 = symkind(s1); k2 = symkind(s2); @@ -539,12 +539,12 @@ scmp(const void *p1, const void *p2) } static void -machogenasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)) +machogenasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*)) { - Sym *s; + LSym *s; genasmsym(put); - for(s=allsym; s; s=s->allsym) + for(s=ctxt->allsym; s; s=s->allsym) if(s->type == SDYNIMPORT || s->type == SHOSTOBJ) if(s->reachable) put(s, nil, 'D', 0, 0, 0, nil); @@ -573,39 +573,54 @@ static void machosymtab(void) { int i; - Sym *symtab, *symstr, *s, *o; + LSym *symtab, *symstr, *s, *o; + char *p; - symtab = lookup(".machosymtab", 0); - symstr = lookup(".machosymstr", 0); + symtab = linklookup(ctxt, ".machosymtab", 0); + symstr = linklookup(ctxt, ".machosymstr", 0); for(i=0; isize); + adduint32(ctxt, symtab, symstr->size); // Only add _ to C symbols. Go symbols have dot in the name. if(strstr(s->extname, ".") == nil) - adduint8(symstr, '_'); - addstring(symstr, s->extname); + adduint8(ctxt, symstr, '_'); + // replace "·" as ".", because DTrace cannot handle it. + if(strstr(s->extname, "·") == nil) { + addstring(symstr, s->extname); + } else { + p = s->extname; + while (*p++ != '\0') { + if((uchar)*p == 0xc2 && (uchar)*(p+1) == 0xb7) { + adduint8(ctxt, symstr, '.'); + p++; + } else { + adduint8(ctxt, symstr, *p); + } + } + adduint8(ctxt, symstr, '\0'); + } if(s->type == SDYNIMPORT || s->type == SHOSTOBJ) { - adduint8(symtab, 0x01); // type N_EXT, external symbol - adduint8(symtab, 0); // no section - adduint16(symtab, 0); // desc - adduintxx(symtab, 0, PtrSize); // no value + adduint8(ctxt, symtab, 0x01); // type N_EXT, external symbol + adduint8(ctxt, symtab, 0); // no section + adduint16(ctxt, symtab, 0); // desc + adduintxx(ctxt, symtab, 0, PtrSize); // no value } else { if(s->cgoexport) - adduint8(symtab, 0x0f); + adduint8(ctxt, symtab, 0x0f); else - adduint8(symtab, 0x0e); + adduint8(ctxt, symtab, 0x0e); o = s; while(o->outer != nil) o = o->outer; if(o->sect == nil) { diag("missing section for %s", s->name); - adduint8(symtab, 0); + adduint8(ctxt, symtab, 0); } else - adduint8(symtab, o->sect->extnum); - adduint16(symtab, 0); // desc - adduintxx(symtab, symaddr(s), PtrSize); + adduint8(ctxt, symtab, o->sect->extnum); + adduint16(ctxt, symtab, 0); // desc + adduintxx(ctxt, symtab, symaddr(s), PtrSize); } } } @@ -615,7 +630,7 @@ machodysymtab(void) { int n; MachoLoad *ml; - Sym *s1, *s2, *s3; + LSym *s1, *s2, *s3; ml = newMachoLoad(11, 18); /* LC_DYSYMTAB */ @@ -639,9 +654,9 @@ machodysymtab(void) ml->data[11] = 0; /* nextrefsyms */ // must match domacholink below - s1 = lookup(".machosymtab", 0); - s2 = lookup(".linkedit.plt", 0); - s3 = lookup(".linkedit.got", 0); + s1 = linklookup(ctxt, ".machosymtab", 0); + s2 = linklookup(ctxt, ".linkedit.plt", 0); + s3 = linklookup(ctxt, ".linkedit.got", 0); ml->data[12] = linkoff + s1->size; /* indirectsymoff */ ml->data[13] = (s2->size + s3->size) / 4; /* nindirectsyms */ @@ -655,15 +670,15 @@ vlong domacholink(void) { int size; - Sym *s1, *s2, *s3, *s4; + LSym *s1, *s2, *s3, *s4; machosymtab(); // write data that will be linkedit section - s1 = lookup(".machosymtab", 0); - s2 = lookup(".linkedit.plt", 0); - s3 = lookup(".linkedit.got", 0); - s4 = lookup(".machosymstr", 0); + s1 = linklookup(ctxt, ".machosymtab", 0); + s2 = linklookup(ctxt, ".linkedit.plt", 0); + s3 = linklookup(ctxt, ".linkedit.got", 0); + s4 = linklookup(ctxt, ".machosymstr", 0); // Force the linkedit section to end on a 16-byte // boundary. This allows pure (non-cgo) Go binaries @@ -683,7 +698,7 @@ domacholink(void) // any alignment padding itself, working around the // issue. while(s4->size%16) - adduint8(s4, 0); + adduint8(ctxt, s4, 0); size = s1->size + s2->size + s3->size + s4->size; @@ -702,9 +717,9 @@ domacholink(void) void -machorelocsect(Section *sect, Sym *first) +machorelocsect(Section *sect, LSym *first) { - Sym *sym; + LSym *sym; int32 eaddr; Reloc *r; @@ -726,7 +741,7 @@ machorelocsect(Section *sect, Sym *first) continue; if(sym->value >= eaddr) break; - cursym = sym; + ctxt->cursym = sym; for(r = sym->r; r < sym->r+sym->nr; r++) { if(r->done) @@ -747,7 +762,7 @@ machoemitreloc(void) while(cpos()&7) cput(0); - machorelocsect(segtext.sect, textp); + machorelocsect(segtext.sect, ctxt->textp); for(sect=segtext.sect->next; sect!=nil; sect=sect->next) machorelocsect(sect, datap); for(sect=segdata.sect; sect!=nil; sect=sect->next) diff --git a/src/cmd/ld/pass.c b/src/cmd/ld/pass.c new file mode 100644 index 000000000..788b7c75a --- /dev/null +++ b/src/cmd/ld/pass.c @@ -0,0 +1,104 @@ +// Inferno utils/6l/pass.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/pass.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. + +// Code and data passes. + +#include "l.h" +#include "../ld/lib.h" +#include "../../pkg/runtime/stack.h" + +void +follow(void) +{ + LSym *s; + + if(debug['v']) + Bprint(&bso, "%5.2f follow\n", cputime()); + Bflush(&bso); + + for(s = ctxt->textp; s != nil; s = s->next) + ctxt->arch->follow(ctxt, s); +} + +void +patch(void) +{ + LSym *s; + + if(debug['v']) + Bprint(&bso, "%5.2f mkfwd\n", cputime()); + Bflush(&bso); + for(s = ctxt->textp; s != nil; s = s->next) + mkfwd(s); + if(debug['v']) + Bprint(&bso, "%5.2f patch\n", cputime()); + Bflush(&bso); + + if(flag_shared) { + s = linklookup(ctxt, "init_array", 0); + s->type = SINITARR; + s->reachable = 1; + s->hide = 1; + addaddr(ctxt, s, linklookup(ctxt, INITENTRY, 0)); + } + + for(s = ctxt->textp; s != nil; s = s->next) + linkpatch(ctxt, s); +} + +void +dostkoff(void) +{ + LSym *s; + + for(s = ctxt->textp; s != nil; s = s->next) + ctxt->arch->addstacksplit(ctxt, s); +} + +void +span(void) +{ + LSym *s; + + if(debug['v']) + Bprint(&bso, "%5.2f span\n", cputime()); + + for(s = ctxt->textp; s != nil; s = s->next) + ctxt->arch->assemble(ctxt, s); +} + +void +pcln(void) +{ + LSym *s; + + for(s = ctxt->textp; s != nil; s = s->next) + linkpcln(ctxt, s); +} diff --git a/src/cmd/ld/pcln.c b/src/cmd/ld/pcln.c new file mode 100644 index 000000000..4c2ffa78e --- /dev/null +++ b/src/cmd/ld/pcln.c @@ -0,0 +1,244 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "l.h" +#include "lib.h" +#include "../../pkg/runtime/funcdata.h" + +static void +addvarint(Pcdata *d, uint32 val) +{ + int32 n; + uint32 v; + uchar *p; + + n = 0; + for(v = val; v >= 0x80; v >>= 7) + n++; + n++; + + if(d->n + n > d->m) { + d->m = (d->n + n)*2; + d->p = erealloc(d->p, d->m); + } + + p = d->p + d->n; + for(v = val; v >= 0x80; v >>= 7) + *p++ = v | 0x80; + *p = v; + d->n += n; +} + +static int32 +addpctab(LSym *ftab, int32 off, Pcdata *d) +{ + int32 start; + + start = ftab->np; + symgrow(ctxt, ftab, start + d->n); + memmove(ftab->p + start, d->p, d->n); + + return setuint32(ctxt, ftab, off, start); +} + +static int32 +ftabaddstring(LSym *ftab, char *s) +{ + int32 n, start; + + n = strlen(s)+1; + start = ftab->np; + symgrow(ctxt, ftab, start+n+1); + strcpy((char*)ftab->p + start, s); + return start; +} + +static void +renumberfiles(Link *ctxt, LSym **files, int nfiles, Pcdata *d) +{ + int i; + LSym *f; + Pcdata out; + Pciter it; + uint32 v; + int32 oldval, newval, val, dv; + + // Give files numbers. + for(i=0; itype != SFILEPATH) { + f->value = ++ctxt->nhistfile; + f->type = SFILEPATH; + f->next = ctxt->filesyms; + ctxt->filesyms = f; + } + } + + newval = -1; + memset(&out, 0, sizeof out); + + for(pciterinit(ctxt, &it, d); !it.done; pciternext(&it)) { + // value delta + oldval = it.value; + if(oldval == -1) + val = -1; + else { + if(oldval < 0 || oldval >= nfiles) + sysfatal("bad pcdata %d", oldval); + val = files[oldval]->value; + } + dv = val - newval; + newval = val; + v = (uint32)(dv<<1) ^ (uint32)(int32)(dv>>31); + addvarint(&out, v); + + // pc delta + addvarint(&out, (it.nextpc - it.pc) / it.pcscale); + } + + // terminating value delta + addvarint(&out, 0); + + free(d->p); + *d = out; +} + + +// pclntab initializes the pclntab symbol with +// runtime function and file name information. +void +pclntab(void) +{ + int32 i, nfunc, start, funcstart; + LSym *ftab, *s; + int32 off, end, frameptrsize; + int64 funcdata_bytes; + Pcln *pcln; + Pciter it; + static Pcln zpcln; + + funcdata_bytes = 0; + ftab = linklookup(ctxt, "pclntab", 0); + ftab->type = SPCLNTAB; + ftab->reachable = 1; + + // See golang.org/s/go12symtab for the format. Briefly: + // 8-byte header + // nfunc [PtrSize bytes] + // function table, alternating PC and offset to func struct [each entry PtrSize bytes] + // end PC [PtrSize bytes] + // offset to file table [4 bytes] + nfunc = 0; + for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next) + nfunc++; + symgrow(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize+4); + setuint32(ctxt, ftab, 0, 0xfffffffb); + setuint8(ctxt, ftab, 6, MINLC); + setuint8(ctxt, ftab, 7, PtrSize); + setuintxx(ctxt, ftab, 8, nfunc, PtrSize); + + nfunc = 0; + for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next, nfunc++) { + pcln = ctxt->cursym->pcln; + if(pcln == nil) + pcln = &zpcln; + + funcstart = ftab->np; + funcstart += -ftab->np & (PtrSize-1); + + setaddr(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize, ctxt->cursym); + setuintxx(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize, funcstart, PtrSize); + + // fixed size of struct, checked below + off = funcstart; + end = funcstart + PtrSize + 3*4 + 5*4 + pcln->npcdata*4 + pcln->nfuncdata*PtrSize; + if(pcln->nfuncdata > 0 && (end&(PtrSize-1))) + end += 4; + symgrow(ctxt, ftab, end); + + // entry uintptr + off = setaddr(ctxt, ftab, off, ctxt->cursym); + + // name int32 + off = setuint32(ctxt, ftab, off, ftabaddstring(ftab, ctxt->cursym->name)); + + // args int32 + // TODO: Move into funcinfo. + off = setuint32(ctxt, ftab, off, ctxt->cursym->args); + + // frame int32 + // TODO: Remove entirely. The pcsp table is more precise. + // This is only used by a fallback case during stack walking + // when a called function doesn't have argument information. + // We need to make sure everything has argument information + // and then remove this. + frameptrsize = PtrSize; + if(ctxt->cursym->leaf) + frameptrsize = 0; + off = setuint32(ctxt, ftab, off, ctxt->cursym->locals + frameptrsize); + + if(pcln != &zpcln) { + renumberfiles(ctxt, pcln->file, pcln->nfile, &pcln->pcfile); + if(0) { + // Sanity check the new numbering + for(pciterinit(ctxt, &it, &pcln->pcfile); !it.done; pciternext(&it)) { + if(it.value < 1 || it.value > ctxt->nhistfile) { + diag("bad file number in pcfile: %d not in range [1, %d]\n", it.value, ctxt->nhistfile); + errorexit(); + } + } + } + } + + // pcdata + off = addpctab(ftab, off, &pcln->pcsp); + off = addpctab(ftab, off, &pcln->pcfile); + off = addpctab(ftab, off, &pcln->pcline); + off = setuint32(ctxt, ftab, off, pcln->npcdata); + off = setuint32(ctxt, ftab, off, pcln->nfuncdata); + for(i=0; inpcdata; i++) + off = addpctab(ftab, off, &pcln->pcdata[i]); + + // funcdata, must be pointer-aligned and we're only int32-aligned. + // Missing funcdata will be 0 (nil pointer). + if(pcln->nfuncdata > 0) { + if(off&(PtrSize-1)) + off += 4; + for(i=0; infuncdata; i++) { + if(pcln->funcdata[i] == nil) + setuintxx(ctxt, ftab, off+PtrSize*i, pcln->funcdataoff[i], PtrSize); + else { + // TODO: Dedup. + funcdata_bytes += pcln->funcdata[i]->size; + setaddrplus(ctxt, ftab, off+PtrSize*i, pcln->funcdata[i], pcln->funcdataoff[i]); + } + } + off += pcln->nfuncdata*PtrSize; + } + + if(off != end) { + diag("bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d ptrsize=%d)", funcstart, off, end, pcln->npcdata, pcln->nfuncdata, PtrSize); + errorexit(); + } + + // Final entry of table is just end pc. + if(ctxt->cursym->next == nil) + setaddrplus(ctxt, ftab, 8+PtrSize+(nfunc+1)*2*PtrSize, ctxt->cursym, ctxt->cursym->size); + } + + // Start file table. + start = ftab->np; + start += -ftab->np & (PtrSize-1); + setuint32(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize, start); + + symgrow(ctxt, ftab, start+(ctxt->nhistfile+1)*4); + setuint32(ctxt, ftab, start, ctxt->nhistfile); + for(s = ctxt->filesyms; s != S; s = s->next) + setuint32(ctxt, ftab, start + s->value*4, ftabaddstring(ftab, s->name)); + + ftab->size = ftab->np; + + if(debug['v']) + Bprint(&bso, "%5.2f pclntab=%lld bytes, funcdata total %lld bytes\n", cputime(), (vlong)ftab->size, (vlong)funcdata_bytes); +} diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c index 7b9a596fc..c26cd5264 100644 --- a/src/cmd/ld/pe.c +++ b/src/cmd/ld/pe.c @@ -32,15 +32,11 @@ static char dosstub[] = 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -// Note: currently only up to 8 chars plus \0. -static char *symlabels[] = { - "symtab", "esymtab", "pclntab", "epclntab" -}; - -static Sym *rsrcsym; +static LSym *rsrcsym; -static char symnames[256]; -static int nextsymoff; +static char* strtbl; +static int strtblnextoff; +static int strtblsize; int32 PESECTHEADR; int32 PEFILEHEADR; @@ -50,6 +46,7 @@ static int nsect; static int nextsectoff; static int nextfileoff; static int textsect; +static int datasect; static IMAGE_FILE_HEADER fh; static IMAGE_OPTIONAL_HEADER oh; @@ -62,7 +59,7 @@ static IMAGE_DATA_DIRECTORY* dd; typedef struct Imp Imp; struct Imp { - Sym* s; + LSym* s; uvlong off; Imp* next; }; @@ -78,9 +75,21 @@ struct Dll { static Dll* dr; -static Sym *dexport[1024]; +static LSym *dexport[1024]; static int nexport; +typedef struct COFFSym COFFSym; +struct COFFSym +{ + LSym* sym; + int strtbloff; + int sect; + vlong value; +}; + +static COFFSym* coffsym; +static int ncoffsym; + static IMAGE_SECTION_HEADER* addpesection(char *name, int sectsize, int filesize) { @@ -191,11 +200,11 @@ initdynimport(void) { Imp *m; Dll *d; - Sym *s, *dynamic; + LSym *s, *dynamic; dr = nil; m = nil; - for(s = allsym; s != S; s = s->allsym) { + for(s = ctxt->allsym; s != S; s = s->allsym) { if(!s->reachable || s->type != SDYNIMPORT) continue; for(d = dr; d != nil; d = d->next) { @@ -216,7 +225,7 @@ initdynimport(void) d->ms = m; } - dynamic = lookup(".windynamic", 0); + dynamic = linklookup(ctxt, ".windynamic", 0); dynamic->reachable = 1; dynamic->type = SWINDOWS; for(d = dr; d != nil; d = d->next) { @@ -241,10 +250,10 @@ addimports(IMAGE_SECTION_HEADER *datsect) vlong startoff, endoff; Imp *m; Dll *d; - Sym* dynamic; + LSym* dynamic; startoff = cpos(); - dynamic = lookup(".windynamic", 0); + dynamic = linklookup(ctxt, ".windynamic", 0); // skip import descriptor table (will write it later) n = 0; @@ -322,20 +331,20 @@ addimports(IMAGE_SECTION_HEADER *datsect) static int scmp(const void *p1, const void *p2) { - Sym *s1, *s2; + LSym *s1, *s2; - s1 = *(Sym**)p1; - s2 = *(Sym**)p2; + s1 = *(LSym**)p1; + s2 = *(LSym**)p2; return strcmp(s1->extname, s2->extname); } static void initdynexport(void) { - Sym *s; + LSym *s; nexport = 0; - for(s = allsym; s != S; s = s->allsym) { + for(s = ctxt->allsym; s != S; s = s->allsym) { if(!s->reachable || !(s->cgoexport & CgoExportDynamic)) continue; if(nexport+1 > sizeof(dexport)/sizeof(dexport[0])) { @@ -410,10 +419,10 @@ addexports(void) void dope(void) { - Sym *rel; + LSym *rel; /* relocation table */ - rel = lookup(".rel", 0); + rel = linklookup(ctxt, ".rel", 0); rel->reachable = 1; rel->type = SELFROSECT; @@ -421,6 +430,24 @@ dope(void) initdynexport(); } +static int +strtbladd(char *name) +{ + int newsize, thisoff; + + newsize = strtblnextoff + strlen(name) + 1; + if(newsize > strtblsize) { + strtblsize = 2 * (newsize + (1<<18)); + strtbl = realloc(strtbl, strtblsize); + } + thisoff = strtblnextoff+4; // first string starts at offset=4 + strcpy(&strtbl[strtblnextoff], name); + strtblnextoff += strlen(name); + strtbl[strtblnextoff] = 0; + strtblnextoff++; + return thisoff; +} + /* * For more than 8 characters section names, name contains a slash (/) that is * followed by an ASCII representation of a decimal number that is an offset into @@ -433,20 +460,13 @@ newPEDWARFSection(char *name, vlong size) { IMAGE_SECTION_HEADER *h; char s[8]; + int off; if(size == 0) return nil; - if(nextsymoff+strlen(name)+1 > sizeof(symnames)) { - diag("pe string table is full"); - errorexit(); - } - - strcpy(&symnames[nextsymoff], name); - sprint(s, "/%d\0", nextsymoff+4); - nextsymoff += strlen(name); - symnames[nextsymoff] = 0; - nextsymoff ++; + off = strtbladd(name); + sprint(s, "/%d\0", off); h = addpesection(s, size, size); h->Characteristics = IMAGE_SCN_MEM_READ| IMAGE_SCN_MEM_DISCARDABLE; @@ -454,41 +474,98 @@ newPEDWARFSection(char *name, vlong size) return h; } +static void +addsym(LSym *s, char *name, int type, vlong addr, vlong size, int ver, LSym *gotype) +{ + COFFSym *cs; + USED(name); + USED(addr); + USED(size); + USED(ver); + USED(gotype); + + if(s == nil) + return; + + if(s->sect == nil) + return; + + switch(type) { + default: + return; + case 'D': + case 'B': + case 'T': + break; + } + + if(coffsym) { + cs = &coffsym[ncoffsym]; + cs->sym = s; + if(strlen(s->name) > 8) + cs->strtbloff = strtbladd(s->name); + if(s->value >= segdata.vaddr) { + cs->value = s->value - segdata.vaddr; + cs->sect = datasect; + } else if(s->value >= segtext.vaddr) { + cs->value = s->value - segtext.vaddr; + cs->sect = textsect; + } else { + cs->value = 0; + cs->sect = 0; + diag("addsym %#llx", addr); + } + } + ncoffsym++; +} + static void addsymtable(void) { IMAGE_SECTION_HEADER *h; int i, size; - Sym *s; - - fh.NumberOfSymbols = sizeof(symlabels)/sizeof(symlabels[0]); - size = nextsymoff + 4 + 18*fh.NumberOfSymbols; + COFFSym *s; + + if(!debug['s']) { + genasmsym(addsym); + coffsym = mal(ncoffsym * sizeof coffsym[0]); + ncoffsym = 0; + genasmsym(addsym); + } + + size = strtblnextoff + 4 + 18*ncoffsym; h = addpesection(".symtab", size, size); h->Characteristics = IMAGE_SCN_MEM_READ| IMAGE_SCN_MEM_DISCARDABLE; chksectoff(h, cpos()); fh.PointerToSymbolTable = cpos(); + fh.NumberOfSymbols = ncoffsym; // put COFF symbol table - for (i=0; iname, 8); - lputl(datoff(s->value)); - wputl(textsect); + for (i=0; istrtbloff == 0) + strnput(s->sym->name, 8); + else { + lputl(0); + lputl(s->strtbloff); + } + lputl(s->value); + wputl(s->sect); wputl(0x0308); // "array of structs" cput(2); // storage class: external cput(0); // no aux entries } // put COFF string table - lputl(nextsymoff + 4); - for (i=0; iSizeOfRawData - size); } void -setpersrc(Sym *sym) +setpersrc(LSym *sym) { if(rsrcsym != nil) diag("too many .rsrc sections"); @@ -529,49 +606,6 @@ addpersrc(void) dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h->VirtualSize; } -static void -addexcept(IMAGE_SECTION_HEADER *text) -{ - IMAGE_SECTION_HEADER *pdata, *xdata; - vlong startoff; - uvlong n; - Sym *sym; - - USED(text); - if(thechar != '6') - return; - - // write unwind info - sym = lookup("runtime.sigtramp", 0); - startoff = cpos(); - lputl(9); // version=1, flags=UNW_FLAG_EHANDLER, rest 0 - lputl(sym->value - PEBASE); - lputl(0); - - n = cpos() - startoff; - xdata = addpesection(".xdata", n, n); - xdata->Characteristics = IMAGE_SCN_MEM_READ| - IMAGE_SCN_CNT_INITIALIZED_DATA; - chksectoff(xdata, startoff); - strnput("", xdata->SizeOfRawData - n); - - // write a function table entry for the whole text segment - startoff = cpos(); - lputl(text->VirtualAddress); - lputl(text->VirtualAddress + text->VirtualSize); - lputl(xdata->VirtualAddress); - - n = cpos() - startoff; - pdata = addpesection(".pdata", n, n); - pdata->Characteristics = IMAGE_SCN_MEM_READ| - IMAGE_SCN_CNT_INITIALIZED_DATA; - chksectoff(pdata, startoff); - strnput("", pdata->SizeOfRawData - n); - - dd[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress = pdata->VirtualAddress; - dd[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size = pdata->VirtualSize; -} - void asmbpe(void) { @@ -600,6 +634,7 @@ asmbpe(void) d->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA| IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE; chksectseg(d, &segdata); + datasect = nsect; if(!debug['s']) dwarfaddpeheaders(); @@ -609,7 +644,6 @@ asmbpe(void) addexports(); addsymtable(); addpersrc(); - addexcept(t); fh.NumberOfSections = nsect; fh.TimeDateStamp = time(0); diff --git a/src/cmd/ld/pe.h b/src/cmd/ld/pe.h index 7aa938829..03ed8d830 100644 --- a/src/cmd/ld/pe.h +++ b/src/cmd/ld/pe.h @@ -176,4 +176,4 @@ typedef struct { IMAGE_DATA_DIRECTORY DataDirectory[16]; } PE64_IMAGE_OPTIONAL_HEADER; -void setpersrc(Sym *sym); +void setpersrc(LSym *sym); diff --git a/src/cmd/ld/pobj.c b/src/cmd/ld/pobj.c new file mode 100644 index 000000000..819c37954 --- /dev/null +++ b/src/cmd/ld/pobj.c @@ -0,0 +1,197 @@ +// 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. + +// 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 + +char *noname = ""; +char* paramspace = "FP"; + +void +main(int argc, char *argv[]) +{ + linkarchinit(); + ctxt = linknew(thelinkarch); + ctxt->thechar = thechar; + ctxt->thestring = thestring; + ctxt->diag = diag; + ctxt->bso = &bso; + + Binit(&bso, 1, OWRITE); + listinit(); + memset(debug, 0, sizeof(debug)); + nerrors = 0; + outfile = nil; + HEADTYPE = -1; + INITTEXT = -1; + INITDAT = -1; + INITRND = -1; + INITENTRY = 0; + linkmode = LinkAuto; + nuxiinit(); + + if(thechar == '5' && ctxt->goarm == 5) + debug['F'] = 1; + + flagcount("1", "use alternate profiling code", &debug['1']); + if(thechar == '6') + flagcount("8", "assume 64-bit addresses", &debug['8']); + flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo); + flagint64("D", "addr: data address", &INITDAT); + flagstr("E", "sym: entry symbol", &INITENTRY); + if(thechar == '5') + flagcount("G", "debug pseudo-ops", &debug['G']); + flagfn1("I", "interp: set ELF interp", setinterp); + flagfn1("L", "dir: add dir to library path", Lflag); + flagfn1("H", "head: header type", setheadtype); + flagcount("K", "add stack underflow checks", &debug['K']); + if(thechar == '5') + flagcount("M", "disable software div/mod", &debug['M']); + flagcount("O", "print pc-line tables", &debug['O']); + flagcount("Q", "debug byte-register code gen", &debug['Q']); + if(thechar == '5') + flagcount("P", "debug code generation", &debug['P']); + flagint32("R", "rnd: address rounding", &INITRND); + flagcount("S", "check type signatures", &debug['S']); + flagint64("T", "addr: text address", &INITTEXT); + flagfn0("V", "print version and exit", doversion); + flagcount("W", "disassemble input", &debug['W']); + flagfn2("X", "name value: define string data", addstrdata); + flagcount("Z", "clear stack frame on entry", &debug['Z']); + flagcount("a", "disassemble output", &debug['a']); + flagcount("c", "dump call graph", &debug['c']); + flagcount("d", "disable dynamic executable", &debug['d']); + flagstr("extld", "linker to run in external mode", &extld); + flagstr("extldflags", "flags for external linker", &extldflags); + flagcount("f", "ignore version mismatch", &debug['f']); + flagcount("g", "disable go package data checks", &debug['g']); + flagstr("installsuffix", "pkg directory suffix", &flag_installsuffix); + flagstr("k", "sym: set field tracking symbol", &tracksym); + flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode); + flagcount("n", "dump symbol table", &debug['n']); + flagstr("o", "outfile: set output file", &outfile); + flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath); + flagcount("race", "enable race detector", &flag_race); + flagcount("s", "disable symbol table", &debug['s']); + if(thechar == '5' || thechar == '6') + flagcount("shared", "generate shared object (implies -linkmode external)", &flag_shared); + flagstr("tmpdir", "leave temporary files in this directory", &tmpdir); + flagcount("u", "reject unsafe packages", &debug['u']); + flagcount("v", "print link trace", &debug['v']); + flagcount("w", "disable DWARF generation", &debug['w']); + + flagparse(&argc, &argv, usage); + ctxt->bso = &bso; + ctxt->debugdivmod = debug['M']; + ctxt->debugfloat = debug['F']; + ctxt->debughist = debug['O']; + ctxt->debugpcln = debug['O']; + ctxt->debugread = debug['W']; + ctxt->debugstack = debug['K']; + ctxt->debugvlog = debug['v']; + + if(argc != 1) + usage(); + + if(outfile == nil) { + if(HEADTYPE == Hwindows) + outfile = smprint("%c.out.exe", thechar); + else + outfile = smprint("%c.out", thechar); + } + libinit(); // creates outfile + + if(HEADTYPE == -1) + HEADTYPE = headtype(goos); + ctxt->headtype = HEADTYPE; + if (headstring == nil) + headstring = headstr(HEADTYPE); + + archinit(); + ctxt->debugfloat = debug['F']; + + if(debug['v']) + Bprint(&bso, "HEADER = -H%d -T0x%llux -D0x%llux -R0x%ux\n", + HEADTYPE, INITTEXT, INITDAT, INITRND); + Bflush(&bso); + + cbp = buf.cbuf; + cbc = sizeof(buf.cbuf); + + addlibpath(ctxt, "command line", "command line", argv[0], "main"); + loadlib(); + + if(thechar == '5') { + // mark some functions that are only referenced after linker code editing + if(debug['F']) + mark(linkrlookup(ctxt, "_sfloat", 0)); + mark(linklookup(ctxt, "runtime.read_tls_fallback", 0)); + } + + deadcode(); + callgraph(); + paramspace = "SP"; /* (FP) now (SP) on output */ + + doelf(); + if(HEADTYPE == Hdarwin) + domacho(); + dostkcheck(); + if(HEADTYPE == Hwindows) + dope(); + addexport(); + textaddress(); + pclntab(); + symtab(); + dodata(); + address(); + doweak(); + reloc(); + asmb(); + undef(); + hostlink(); + if(debug['v']) { + Bprint(&bso, "%5.2f cpu time\n", cputime()); + Bprint(&bso, "%d symbols\n", ctxt->nsymbol); + Bprint(&bso, "%d sizeof adr\n", sizeof(Addr)); + Bprint(&bso, "%d sizeof prog\n", sizeof(Prog)); + Bprint(&bso, "%lld liveness data\n", liveness); + } + Bflush(&bso); + + errorexit(); +} diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c index c9b4657f7..6d321c0bb 100644 --- a/src/cmd/ld/symtab.c +++ b/src/cmd/ld/symtab.c @@ -40,6 +40,7 @@ static int putelfstr(char *s) { int off, n; + char *p, *q; if(elfstrsize == 0 && s[0] != 0) { // first entry must be empty string @@ -54,6 +55,21 @@ putelfstr(char *s) off = elfstrsize; elfstrsize += n; memmove(elfstrdat+off, s, n); + // replace "·" as ".", because DTrace cannot handle it. + p = strstr(s, "·"); + if(p != nil) { + p = q = elfstrdat+off; + while (*q != '\0') { + if((uchar)*q == 0xc2 && (uchar)*(q+1) == 0xb7) { + q += 2; + *p++ = '.'; + elfstrsize--; + } else { + *p++ = *q++; + } + } + *p = '\0'; + } return off; } @@ -86,10 +102,10 @@ static int numelfsym = 1; // 0 is reserved static int elfbind; static void -putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) +putelfsym(LSym *x, char *s, int t, vlong addr, vlong size, int ver, LSym *go) { int bind, type, off; - Sym *xo; + LSym *xo; USED(go); switch(t) { @@ -109,12 +125,12 @@ putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) while(xo->outer != nil) xo = xo->outer; if(xo->sect == nil) { - cursym = x; + ctxt->cursym = x; diag("missing section in putelfsym"); return; } if(xo->sect->elfsect == nil) { - cursym = x; + ctxt->cursym = x; diag("missing ELF section in putelfsym"); return; } @@ -143,7 +159,7 @@ putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) } void -putelfsectionsym(Sym* s, int shndx) +putelfsectionsym(LSym* s, int shndx) { putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_SECTION, shndx, 0); s->elfsym = numelfsym++; @@ -170,7 +186,8 @@ putelfsymshndx(vlong sympos, int shndx) void asmelfsym(void) { - Sym *s; + LSym *s; + char *name; // the first symbol entry is reserved putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_NOTYPE, 0, 0); @@ -181,9 +198,9 @@ asmelfsym(void) genasmsym(putelfsym); if(linkmode == LinkExternal && HEADTYPE != Hopenbsd) { - s = lookup("runtime.tlsgm", 0); + s = linklookup(ctxt, "runtime.tlsgm", 0); if(s->sect == nil) { - cursym = nil; + ctxt->cursym = nil; diag("missing section for %s", s->name); errorexit(); } @@ -195,16 +212,20 @@ asmelfsym(void) elfglobalsymndx = numelfsym; genasmsym(putelfsym); - for(s=allsym; s!=S; s=s->allsym) { - if(s->type != SHOSTOBJ) + for(s=ctxt->allsym; s!=S; s=s->allsym) { + if(s->type != SHOSTOBJ && !(s->type == SDYNIMPORT && s->reachable)) continue; - putelfsyment(putelfstr(s->name), 0, 0, (STB_GLOBAL<<4)|STT_NOTYPE, 0, 0); + if(s->type == SDYNIMPORT) + name = s->extname; + else + name = s->name; + putelfsyment(putelfstr(name), 0, 0, (STB_GLOBAL<<4)|STT_NOTYPE, 0, 0); s->elfsym = numelfsym++; } } static void -putplan9sym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) +putplan9sym(LSym *x, char *s, int t, vlong addr, vlong size, int ver, LSym *go) { int i, l; @@ -226,7 +247,7 @@ putplan9sym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) case 'Z': case 'm': l = 4; - if(HEADTYPE == Hplan9x64 && !debug['8']) { + if(HEADTYPE == Hplan9 && thechar == '6' && !debug['8']) { lputb(addr>>32); l = 8; } @@ -263,48 +284,7 @@ asmplan9sym(void) genasmsym(putplan9sym); } -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; -} - -static void -slputl(int32 v) -{ - uchar *p; - - symgrow(symt, symt->size+4); - p = symt->p + symt->size; - *p++ = v; - *p++ = v>>8; - *p++ = v>>16; - *p = v>>24; - symt->size += 4; -} - -static void (*slput)(int32); +static LSym *symt; void wputl(ushort w) @@ -352,112 +332,10 @@ vputl(uint64 v) lputl(v >> 32); } -// Emit symbol table entry. -// The table format is described at the top of ../../pkg/runtime/symtab.c. -void -putsymb(Sym *s, char *name, int t, vlong v, vlong size, int ver, Sym *typ) -{ - int i, f, c; - vlong v1; - Reloc *rel; - - USED(size); - - // type byte - if('A' <= t && t <= 'Z') - c = t - 'A' + (ver ? 26 : 0); - else if('a' <= t && t <= 'z') - c = t - 'a' + 26; - else { - diag("invalid symbol table type %c", t); - errorexit(); - return; - } - - if(s != nil) - c |= 0x40; // wide value - if(typ != nil) - c |= 0x80; // has go type - scput(c); - - // value - if(s != nil) { - // full width - rel = addrel(symt); - rel->siz = PtrSize; - rel->sym = s; - rel->type = D_ADDR; - rel->off = symt->size; - if(PtrSize == 8) - slput(0); - slput(0); - } else { - // varint - if(v < 0) { - diag("negative value in symbol table: %s %lld", name, v); - errorexit(); - } - v1 = v; - while(v1 >= 0x80) { - scput(v1 | 0x80); - v1 >>= 7; - } - scput(v1); - } - - // go type if present - if(typ != nil) { - if(!typ->reachable) - diag("unreachable type %s", typ->name); - rel = addrel(symt); - rel->siz = PtrSize; - rel->sym = typ; - rel->type = D_ADDR; - rel->off = symt->size; - if(PtrSize == 8) - slput(0); - slput(0); - } - - // name - if(t == 'f') - name++; - - 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); - } else { - for(i=0; name[i]; i++) - scput(name[i]); - scput(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, name, ver, typ ? typ->name : ""); - else - Bprint(&bso, "%c %.8llux %s %s\n", t, v, name, typ ? typ->name : ""); - } -} - void symtab(void) { - Sym *s, *symtype, *symtypelink, *symgostring, *symgofunc; + LSym *s, *symtype, *symtypelink, *symgostring, *symgofunc; dosymtype(); @@ -482,40 +360,40 @@ symtab(void) xdefine("esymtab", SRODATA, 0); // garbage collection symbols - s = lookup("gcdata", 0); + s = linklookup(ctxt, "gcdata", 0); s->type = SRODATA; s->size = 0; s->reachable = 1; xdefine("egcdata", SRODATA, 0); - s = lookup("gcbss", 0); + s = linklookup(ctxt, "gcbss", 0); s->type = SRODATA; s->size = 0; s->reachable = 1; xdefine("egcbss", SRODATA, 0); // pseudo-symbols to mark locations of type, string, and go string data. - s = lookup("type.*", 0); + s = linklookup(ctxt, "type.*", 0); s->type = STYPE; s->size = 0; s->reachable = 1; symtype = s; - s = lookup("go.string.*", 0); + s = linklookup(ctxt, "go.string.*", 0); s->type = SGOSTRING; s->size = 0; s->reachable = 1; symgostring = s; - s = lookup("go.func.*", 0); + s = linklookup(ctxt, "go.func.*", 0); s->type = SGOFUNC; s->size = 0; s->reachable = 1; symgofunc = s; - symtypelink = lookup("typelink", 0); + symtypelink = linklookup(ctxt, "typelink", 0); - symt = lookup("symtab", 0); + symt = linklookup(ctxt, "symtab", 0); symt->type = SSYMTAB; symt->size = 0; symt->reachable = 1; @@ -524,7 +402,7 @@ symtab(void) // within a type they sort by size, so the .* symbols // just defined above will be first. // hide the specific symbols. - for(s = allsym; s != S; s = s->allsym) { + for(s = ctxt->allsym; s != S; s = s->allsym) { if(!s->reachable || s->special || s->type != SRODATA) continue; if(strncmp(s->name, "type.", 5) == 0) { @@ -547,32 +425,12 @@ symtab(void) s->hide = 1; s->outer = symgofunc; } + if(strncmp(s->name, "gcargs.", 7) == 0 || strncmp(s->name, "gclocals.", 9) == 0 || strncmp(s->name, "gclocals·", 10) == 0) { + s->type = SGOFUNC; + s->hide = 1; + s->outer = symgofunc; + s->align = 4; + liveness += (s->size+s->align-1)&~(s->align-1); + } } - - if(debug['s']) - return; - - switch(thechar) { - default: - diag("unknown architecture %c", thechar); - errorexit(); - case '5': - case '6': - case '8': - // little-endian symbol table - slput = slputl; - break; - case 'v': - // big-endian symbol table - slput = slputb; - break; - } - // new symbol table header. - slput(0xfffffffd); - scput(0); - scput(0); - scput(0); - scput(PtrSize); - - genasmsym(putsymb); } diff --git a/src/cmd/ld/textflag.h b/src/cmd/ld/textflag.h index 1d62db736..2a76e76c2 100644 --- a/src/cmd/ld/textflag.h +++ b/src/cmd/ld/textflag.h @@ -19,3 +19,5 @@ #define NOPTR 16 // This is a wrapper function and should not count as disabling 'recover'. #define WRAPPER 32 +// This function uses its incoming context register. +#define NEEDCTXT 64 diff --git a/src/cmd/nm/Makefile b/src/cmd/nm/Makefile deleted file mode 100644 index 3f528d751..000000000 --- a/src/cmd/nm/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright 2012 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.dist diff --git a/src/cmd/nm/debug_goobj.go b/src/cmd/nm/debug_goobj.go new file mode 100644 index 000000000..9a067e2b9 --- /dev/null +++ b/src/cmd/nm/debug_goobj.go @@ -0,0 +1,670 @@ +// DO NOT EDIT. Generated by code.google.com/p/rsc/cmd/bundle +// bundle -p main -x goobj_ debug/goobj + +/* read.go */ + +// Copyright 2013 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 goobj implements reading of Go object files and archives. +// +// TODO(rsc): Decide where this package should live. (golang.org/issue/6932) +// TODO(rsc): Decide the appropriate integer types for various fields. +// TODO(rsc): Write tests. (File format still up in the air a little.) + +package main + +import ( + "bufio" + "bytes" + "errors" + "fmt" + "io" + "strconv" + "strings" +) + +// A SymKind describes the kind of memory represented by a symbol. +type goobj_SymKind int + +// This list is taken from include/link.h. + +// Defined SymKind values. +// TODO(rsc): Give idiomatic Go names. +// TODO(rsc): Reduce the number of symbol types in the object files. +const ( + _ goobj_SymKind = iota + + // readonly, executable + goobj_STEXT + goobj_SELFRXSECT + + // readonly, non-executable + goobj_STYPE + goobj_SSTRING + goobj_SGOSTRING + goobj_SGOFUNC + goobj_SRODATA + goobj_SFUNCTAB + goobj_STYPELINK + goobj_SSYMTAB // TODO: move to unmapped section + goobj_SPCLNTAB + goobj_SELFROSECT + + // writable, non-executable + goobj_SMACHOPLT + goobj_SELFSECT + goobj_SMACHO // Mach-O __nl_symbol_ptr + goobj_SMACHOGOT + goobj_SNOPTRDATA + goobj_SINITARR + goobj_SDATA + goobj_SWINDOWS + goobj_SBSS + goobj_SNOPTRBSS + goobj_STLSBSS + + // not mapped + goobj_SXREF + goobj_SMACHOSYMSTR + goobj_SMACHOSYMTAB + goobj_SMACHOINDIRECTPLT + goobj_SMACHOINDIRECTGOT + goobj_SFILE + goobj_SFILEPATH + goobj_SCONST + goobj_SDYNIMPORT + goobj_SHOSTOBJ +) + +var goobj_symKindStrings = []string{ + goobj_SBSS: "SBSS", + goobj_SCONST: "SCONST", + goobj_SDATA: "SDATA", + goobj_SDYNIMPORT: "SDYNIMPORT", + goobj_SELFROSECT: "SELFROSECT", + goobj_SELFRXSECT: "SELFRXSECT", + goobj_SELFSECT: "SELFSECT", + goobj_SFILE: "SFILE", + goobj_SFILEPATH: "SFILEPATH", + goobj_SFUNCTAB: "SFUNCTAB", + goobj_SGOFUNC: "SGOFUNC", + goobj_SGOSTRING: "SGOSTRING", + goobj_SHOSTOBJ: "SHOSTOBJ", + goobj_SINITARR: "SINITARR", + goobj_SMACHO: "SMACHO", + goobj_SMACHOGOT: "SMACHOGOT", + goobj_SMACHOINDIRECTGOT: "SMACHOINDIRECTGOT", + goobj_SMACHOINDIRECTPLT: "SMACHOINDIRECTPLT", + goobj_SMACHOPLT: "SMACHOPLT", + goobj_SMACHOSYMSTR: "SMACHOSYMSTR", + goobj_SMACHOSYMTAB: "SMACHOSYMTAB", + goobj_SNOPTRBSS: "SNOPTRBSS", + goobj_SNOPTRDATA: "SNOPTRDATA", + goobj_SPCLNTAB: "SPCLNTAB", + goobj_SRODATA: "SRODATA", + goobj_SSTRING: "SSTRING", + goobj_SSYMTAB: "SSYMTAB", + goobj_STEXT: "STEXT", + goobj_STLSBSS: "STLSBSS", + goobj_STYPE: "STYPE", + goobj_STYPELINK: "STYPELINK", + goobj_SWINDOWS: "SWINDOWS", + goobj_SXREF: "SXREF", +} + +func (k goobj_SymKind) String() string { + if k < 0 || int(k) >= len(goobj_symKindStrings) { + return fmt.Sprintf("SymKind(%d)", k) + } + return goobj_symKindStrings[k] +} + +// A Sym is a named symbol in an object file. +type goobj_Sym struct { + goobj_SymID // symbol identifier (name and version) + Kind goobj_SymKind // kind of symbol + DupOK bool // are duplicate definitions okay? + Size int // size of corresponding data + Type goobj_SymID // symbol for Go type information + Data goobj_Data // memory image of symbol + Reloc []goobj_Reloc // relocations to apply to Data + Func *goobj_Func // additional data for functions +} + +// A SymID - the combination of Name and Version - uniquely identifies +// a symbol within a package. +type goobj_SymID struct { + // Name is the name of a symbol. + Name string + + // Version is zero for symbols with global visibility. + // Symbols with only file visibility (such as file-level static + // declarations in C) have a non-zero version distinguishing + // a symbol in one file from a symbol of the same name + // in another file + Version int +} + +func (s goobj_SymID) String() string { + if s.Version == 0 { + return s.Name + } + return fmt.Sprintf("%s<%d>", s.Name, s.Version) +} + +// A Data is a reference to data stored in an object file. +// It records the offset and size of the data, so that a client can +// read the data only if necessary. +type goobj_Data struct { + Offset int64 + Size int64 +} + +// A Reloc describes a relocation applied to a memory image to refer +// to an address within a particular symbol. +type goobj_Reloc struct { + // The bytes at [Offset, Offset+Size) within the memory image + // should be updated to refer to the address Add bytes after the start + // of the symbol Sym. + Offset int + Size int + Sym goobj_SymID + Add int + + // The Type records the form of address expected in the bytes + // described by the previous fields: absolute, PC-relative, and so on. + // TODO(rsc): The interpretation of Type is not exposed by this package. + Type int +} + +// A Var describes a variable in a function stack frame: a declared +// local variable, an input argument, or an output result. +type goobj_Var struct { + // The combination of Name, Kind, and Offset uniquely + // identifies a variable in a function stack frame. + // Using fewer of these - in particular, using only Name - does not. + Name string // Name of variable. + Kind int // TODO(rsc): Define meaning. + Offset int // Frame offset. TODO(rsc): Define meaning. + + Type goobj_SymID // Go type for variable. +} + +// Func contains additional per-symbol information specific to functions. +type goobj_Func struct { + Args int // size in bytes of argument frame: inputs and outputs + Frame int // size in bytes of local variable frame + Leaf bool // function omits save of link register (ARM) + NoSplit bool // function omits stack split prologue + Var []goobj_Var // detail about local variables + PCSP goobj_Data // PC → SP offset map + PCFile goobj_Data // PC → file number map (index into File) + PCLine goobj_Data // PC → line number map + PCData []goobj_Data // PC → runtime support data map + FuncData []goobj_FuncData // non-PC-specific runtime support data + File []string // paths indexed by PCFile +} + +// TODO: Add PCData []byte and PCDataIter (similar to liblink). + +// A FuncData is a single function-specific data value. +type goobj_FuncData struct { + Sym goobj_SymID // symbol holding data + Offset int64 // offset into symbol for funcdata pointer +} + +// A Package is a parsed Go object file or archive defining a Go package. +type goobj_Package struct { + ImportPath string // import path denoting this package + Imports []string // packages imported by this package + Syms []*goobj_Sym // symbols defined by this package + MaxVersion int // maximum Version in any SymID in Syms +} + +var ( + goobj_archiveHeader = []byte("!\n") + goobj_archiveMagic = []byte("`\n") + goobj_goobjHeader = []byte("go objec") // truncated to size of archiveHeader + + goobj_errCorruptArchive = errors.New("corrupt archive") + goobj_errTruncatedArchive = errors.New("truncated archive") + goobj_errNotArchive = errors.New("unrecognized archive format") + + goobj_errCorruptObject = errors.New("corrupt object file") + goobj_errTruncatedObject = errors.New("truncated object file") + goobj_errNotObject = errors.New("unrecognized object file format") +) + +// An objReader is an object file reader. +type goobj_objReader struct { + p *goobj_Package + b *bufio.Reader + f io.ReadSeeker + err error + offset int64 + limit int64 + tmp [256]byte + pkg string + pkgprefix string +} + +// importPathToPrefix returns the prefix that will be used in the +// final symbol table for the given import path. +// We escape '%', '"', all control characters and non-ASCII bytes, +// and any '.' after the final slash. +// +// See ../../../cmd/ld/lib.c:/^pathtoprefix and +// ../../../cmd/gc/subr.c:/^pathtoprefix. +func goobj_importPathToPrefix(s string) string { + // find index of last slash, if any, or else -1. + // used for determining whether an index is after the last slash. + slash := strings.LastIndex(s, "/") + + // check for chars that need escaping + n := 0 + for r := 0; r < len(s); r++ { + if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F { + n++ + } + } + + // quick exit + if n == 0 { + return s + } + + // escape + const hex = "0123456789abcdef" + p := make([]byte, 0, len(s)+2*n) + for r := 0; r < len(s); r++ { + if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F { + p = append(p, '%', hex[c>>4], hex[c&0xF]) + } else { + p = append(p, c) + } + } + + return string(p) +} + +// init initializes r to read package p from f. +func (r *goobj_objReader) init(f io.ReadSeeker, p *goobj_Package) { + r.f = f + r.p = p + r.offset, _ = f.Seek(0, 1) + r.limit, _ = f.Seek(0, 2) + f.Seek(r.offset, 0) + r.b = bufio.NewReader(f) + r.pkgprefix = goobj_importPathToPrefix(p.ImportPath) + "." +} + +// error records that an error occurred. +// It returns only the first error, so that an error +// caused by an earlier error does not discard information +// about the earlier error. +func (r *goobj_objReader) error(err error) error { + if r.err == nil { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + r.err = err + } + // panic("corrupt") // useful for debugging + return r.err +} + +// readByte reads and returns a byte from the input file. +// On I/O error or EOF, it records the error but returns byte 0. +// A sequence of 0 bytes will eventually terminate any +// parsing state in the object file. In particular, it ends the +// reading of a varint. +func (r *goobj_objReader) readByte() byte { + if r.err != nil { + return 0 + } + if r.offset >= r.limit { + r.error(io.ErrUnexpectedEOF) + return 0 + } + b, err := r.b.ReadByte() + if err != nil { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + r.error(err) + b = 0 + } else { + r.offset++ + } + return b +} + +// read reads exactly len(b) bytes from the input file. +// If an error occurs, read returns the error but also +// records it, so it is safe for callers to ignore the result +// as long as delaying the report is not a problem. +func (r *goobj_objReader) readFull(b []byte) error { + if r.err != nil { + return r.err + } + if r.offset+int64(len(b)) > r.limit { + return r.error(io.ErrUnexpectedEOF) + } + n, err := io.ReadFull(r.b, b) + r.offset += int64(n) + if err != nil { + return r.error(err) + } + return nil +} + +// readInt reads a zigzag varint from the input file. +func (r *goobj_objReader) readInt() int { + var u uint64 + + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + r.error(goobj_errCorruptObject) + return 0 + } + c := r.readByte() + u |= uint64(c&0x7F) << shift + if c&0x80 == 0 { + break + } + } + + v := int64(u>>1) ^ (int64(u) << 63 >> 63) + if int64(int(v)) != v { + r.error(goobj_errCorruptObject) // TODO + return 0 + } + return int(v) +} + +// readString reads a length-delimited string from the input file. +func (r *goobj_objReader) readString() string { + n := r.readInt() + buf := make([]byte, n) + r.readFull(buf) + return string(buf) +} + +// readSymID reads a SymID from the input file. +func (r *goobj_objReader) readSymID() goobj_SymID { + name, vers := r.readString(), r.readInt() + + // In a symbol name in an object file, "". denotes the + // prefix for the package in which the object file has been found. + // Expand it. + name = strings.Replace(name, `"".`, r.pkgprefix, -1) + + // An individual object file only records version 0 (extern) or 1 (static). + // To make static symbols unique across all files being read, we + // replace version 1 with the version corresponding to the current + // file number. The number is incremented on each call to parseObject. + if vers != 0 { + vers = r.p.MaxVersion + } + + return goobj_SymID{name, vers} +} + +// readData reads a data reference from the input file. +func (r *goobj_objReader) readData() goobj_Data { + n := r.readInt() + d := goobj_Data{Offset: r.offset, Size: int64(n)} + r.skip(int64(n)) + return d +} + +// skip skips n bytes in the input. +func (r *goobj_objReader) skip(n int64) { + if n < 0 { + r.error(fmt.Errorf("debug/goobj: internal error: misuse of skip")) + } + if n < int64(len(r.tmp)) { + // Since the data is so small, a just reading from the buffered + // reader is better than flushing the buffer and seeking. + r.readFull(r.tmp[:n]) + } else if n <= int64(r.b.Buffered()) { + // Even though the data is not small, it has already been read. + // Advance the buffer instead of seeking. + for n > int64(len(r.tmp)) { + r.readFull(r.tmp[:]) + n -= int64(len(r.tmp)) + } + r.readFull(r.tmp[:n]) + } else { + // Seek, giving up buffered data. + _, err := r.f.Seek(r.offset+n, 0) + if err != nil { + r.error(err) + } + r.offset += n + r.b.Reset(r.f) + } +} + +// Parse parses an object file or archive from r, +// assuming that its import path is pkgpath. +func goobj_Parse(r io.ReadSeeker, pkgpath string) (*goobj_Package, error) { + if pkgpath == "" { + pkgpath = `""` + } + p := new(goobj_Package) + p.ImportPath = pkgpath + + var rd goobj_objReader + rd.init(r, p) + err := rd.readFull(rd.tmp[:8]) + if err != nil { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + return nil, err + } + + switch { + default: + return nil, goobj_errNotObject + + case bytes.Equal(rd.tmp[:8], goobj_archiveHeader): + if err := rd.parseArchive(); err != nil { + return nil, err + } + case bytes.Equal(rd.tmp[:8], goobj_goobjHeader): + if err := rd.parseObject(goobj_goobjHeader); err != nil { + return nil, err + } + } + + return p, nil +} + +// trimSpace removes trailing spaces from b and returns the corresponding string. +// This effectively parses the form used in archive headers. +func goobj_trimSpace(b []byte) string { + return string(bytes.TrimRight(b, " ")) +} + +// parseArchive parses a Unix archive of Go object files. +// TODO(rsc): Need to skip non-Go object files. +// TODO(rsc): Maybe record table of contents in r.p so that +// linker can avoid having code to parse archives too. +func (r *goobj_objReader) parseArchive() error { + for r.offset < r.limit { + if err := r.readFull(r.tmp[:60]); err != nil { + return err + } + data := r.tmp[:60] + + // Each file is preceded by this text header (slice indices in first column): + // 0:16 name + // 16:28 date + // 28:34 uid + // 34:40 gid + // 40:48 mode + // 48:58 size + // 58:60 magic - `\n + // We only care about name, size, and magic. + // The fields are space-padded on the right. + // The size is in decimal. + // The file data - size bytes - follows the header. + // Headers are 2-byte aligned, so if size is odd, an extra padding + // byte sits between the file data and the next header. + // The file data that follows is padded to an even number of bytes: + // if size is odd, an extra padding byte is inserted betw the next header. + if len(data) < 60 { + return goobj_errTruncatedArchive + } + if !bytes.Equal(data[58:60], goobj_archiveMagic) { + return goobj_errCorruptArchive + } + name := goobj_trimSpace(data[0:16]) + size, err := strconv.ParseInt(goobj_trimSpace(data[48:58]), 10, 64) + if err != nil { + return goobj_errCorruptArchive + } + data = data[60:] + fsize := size + size&1 + if fsize < 0 || fsize < size { + return goobj_errCorruptArchive + } + switch name { + case "__.SYMDEF", "__.GOSYMDEF", "__.PKGDEF": + r.skip(size) + default: + oldLimit := r.limit + r.limit = r.offset + size + if err := r.parseObject(nil); err != nil { + return fmt.Errorf("parsing archive member %q: %v", name, err) + } + r.skip(r.limit - r.offset) + r.limit = oldLimit + } + if size&1 != 0 { + r.skip(1) + } + } + return nil +} + +// parseObject parses a single Go object file. +// The prefix is the bytes already read from the file, +// typically in order to detect that this is an object file. +// The object file consists of a textual header ending in "\n!\n" +// and then the part we want to parse begins. +// The format of that part is defined in a comment at the top +// of src/liblink/objfile.c. +func (r *goobj_objReader) parseObject(prefix []byte) error { + // TODO(rsc): Maybe use prefix and the initial input to + // record the header line from the file, which would + // give the architecture and other version information. + + r.p.MaxVersion++ + var c1, c2, c3 byte + for { + c1, c2, c3 = c2, c3, r.readByte() + if c3 == 0 { // NUL or EOF, either is bad + return goobj_errCorruptObject + } + if c1 == '\n' && c2 == '!' && c3 == '\n' { + break + } + } + + r.readFull(r.tmp[:8]) + if !bytes.Equal(r.tmp[:8], []byte("\x00\x00go13ld")) { + return r.error(goobj_errCorruptObject) + } + + b := r.readByte() + if b != 1 { + return r.error(goobj_errCorruptObject) + } + + // Direct package dependencies. + for { + s := r.readString() + if s == "" { + break + } + r.p.Imports = append(r.p.Imports, s) + } + + // Symbols. + for { + if b := r.readByte(); b != 0xfe { + if b != 0xff { + return r.error(goobj_errCorruptObject) + } + break + } + + typ := r.readInt() + s := &goobj_Sym{goobj_SymID: r.readSymID()} + r.p.Syms = append(r.p.Syms, s) + s.Kind = goobj_SymKind(typ) + s.DupOK = r.readInt() != 0 + s.Size = r.readInt() + s.Type = r.readSymID() + s.Data = r.readData() + s.Reloc = make([]goobj_Reloc, r.readInt()) + for i := range s.Reloc { + rel := &s.Reloc[i] + rel.Offset = r.readInt() + rel.Size = r.readInt() + rel.Type = r.readInt() + rel.Add = r.readInt() + r.readInt() // Xadd - ignored + rel.Sym = r.readSymID() + r.readSymID() // Xsym - ignored + } + + if s.Kind == goobj_STEXT { + f := new(goobj_Func) + s.Func = f + f.Args = r.readInt() + f.Frame = r.readInt() + f.Leaf = r.readInt() != 0 + f.NoSplit = r.readInt() != 0 + f.Var = make([]goobj_Var, r.readInt()) + for i := range f.Var { + v := &f.Var[i] + v.Name = r.readSymID().Name + v.Offset = r.readInt() + v.Kind = r.readInt() + v.Type = r.readSymID() + } + + f.PCSP = r.readData() + f.PCFile = r.readData() + f.PCLine = r.readData() + f.PCData = make([]goobj_Data, r.readInt()) + for i := range f.PCData { + f.PCData[i] = r.readData() + } + f.FuncData = make([]goobj_FuncData, r.readInt()) + for i := range f.FuncData { + f.FuncData[i].Sym = r.readSymID() + } + for i := range f.FuncData { + f.FuncData[i].Offset = int64(r.readInt()) // TODO + } + f.File = make([]string, r.readInt()) + for i := range f.File { + f.File[i] = r.readSymID().Name + } + } + } + + r.readFull(r.tmp[:7]) + if !bytes.Equal(r.tmp[:7], []byte("\xffgo13ld")) { + return r.error(goobj_errCorruptObject) + } + + return nil +} diff --git a/src/cmd/nm/doc.go b/src/cmd/nm/doc.go index 8e88e2e63..b62da47c0 100644 --- a/src/cmd/nm/doc.go +++ b/src/cmd/nm/doc.go @@ -1,23 +1,41 @@ -// Copyright 2009 The Go Authors. All rights reserved. +// Copyright 2013 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. -// +build ignore - -/* - -Nm is a version of the Plan 9 nm command. The original is documented at - - http://plan9.bell-labs.com/magic/man2html/1/nm - -It prints the name list (symbol table) for programs compiled by gc as well as the -Plan 9 C compiler. - -This implementation adds the flag -S, which prints each symbol's size -in decimal after its address. - -Usage: - go tool nm [-aghnsSTu] file - -*/ +// Nm lists the symbols defined or used by an object file, archive, or executable. +// +// Usage: +// go tool nm [options] file... +// +// The default output prints one line per symbol, with three space-separated +// fields giving the address (in hexadecimal), type (a character), and name of +// the symbol. The types are: +// +// T text (code) segment symbol +// t static text segment symbol +// R read-only data segment symbol +// r static read-only data segment symbol +// D data segment symbol +// d static data segment symbol +// B bss segment symbol +// b static bss segment symbol +// C constant address +// U referenced but undefined symbol +// +// Following established convention, the address is omitted for undefined +// symbols (type U). +// +// The options control the printed output: +// +// -n +// an alias for -sort address (numeric), +// for compatibility with other nm commands +// -size +// print symbol size in decimal between address and type +// -sort {address,name,none,size} +// sort output in the given order (default name) +// size orders from largest to smallest +// -type +// print symbol type after name +// package main diff --git a/src/cmd/nm/elf.go b/src/cmd/nm/elf.go new file mode 100644 index 000000000..5aaa194dd --- /dev/null +++ b/src/cmd/nm/elf.go @@ -0,0 +1,57 @@ +// Copyright 2013 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. + +// Parsing of ELF executables (Linux, FreeBSD, and so on). + +package main + +import ( + "debug/elf" + "os" +) + +func elfSymbols(f *os.File) []Sym { + p, err := elf.NewFile(f) + if err != nil { + errorf("parsing %s: %v", f.Name(), err) + return nil + } + + elfSyms, err := p.Symbols() + if err != nil { + errorf("parsing %s: %v", f.Name(), err) + return nil + } + + var syms []Sym + for _, s := range elfSyms { + sym := Sym{Addr: s.Value, Name: s.Name, Size: int64(s.Size), Code: '?'} + switch s.Section { + case elf.SHN_UNDEF: + sym.Code = 'U' + case elf.SHN_COMMON: + sym.Code = 'B' + default: + i := int(s.Section) + if i < 0 || i >= len(p.Sections) { + break + } + sect := p.Sections[i] + switch sect.Flags & (elf.SHF_WRITE | elf.SHF_ALLOC | elf.SHF_EXECINSTR) { + case elf.SHF_ALLOC | elf.SHF_EXECINSTR: + sym.Code = 'T' + case elf.SHF_ALLOC: + sym.Code = 'R' + case elf.SHF_ALLOC | elf.SHF_WRITE: + sym.Code = 'D' + } + } + if elf.ST_BIND(s.Info) == elf.STB_LOCAL { + sym.Code += 'a' - 'A' + } + syms = append(syms, sym) + } + + return syms +} diff --git a/src/cmd/nm/goobj.go b/src/cmd/nm/goobj.go new file mode 100644 index 000000000..5e0817d95 --- /dev/null +++ b/src/cmd/nm/goobj.go @@ -0,0 +1,67 @@ +// Copyright 2013 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. + +// Parsing of Go intermediate object files and archives. + +package main + +import ( + "fmt" + "os" +) + +func goobjName(id goobj_SymID) string { + if id.Version == 0 { + return id.Name + } + return fmt.Sprintf("%s<%d>", id.Name, id.Version) +} + +func goobjSymbols(f *os.File) []Sym { + pkg, err := goobj_Parse(f, `""`) + if err != nil { + errorf("parsing %s: %v", f.Name(), err) + return nil + } + + seen := make(map[goobj_SymID]bool) + + var syms []Sym + for _, s := range pkg.Syms { + seen[s.goobj_SymID] = true + sym := Sym{Addr: uint64(s.Data.Offset), Name: goobjName(s.goobj_SymID), Size: int64(s.Size), Type: s.Type.Name, Code: '?'} + switch s.Kind { + case goobj_STEXT, goobj_SELFRXSECT: + sym.Code = 'T' + case goobj_STYPE, goobj_SSTRING, goobj_SGOSTRING, goobj_SGOFUNC, goobj_SRODATA, goobj_SFUNCTAB, goobj_STYPELINK, goobj_SSYMTAB, goobj_SPCLNTAB, goobj_SELFROSECT: + sym.Code = 'R' + case goobj_SMACHOPLT, goobj_SELFSECT, goobj_SMACHO, goobj_SMACHOGOT, goobj_SNOPTRDATA, goobj_SINITARR, goobj_SDATA, goobj_SWINDOWS: + sym.Code = 'D' + case goobj_SBSS, goobj_SNOPTRBSS, goobj_STLSBSS: + sym.Code = 'B' + case goobj_SXREF, goobj_SMACHOSYMSTR, goobj_SMACHOSYMTAB, goobj_SMACHOINDIRECTPLT, goobj_SMACHOINDIRECTGOT, goobj_SFILE, goobj_SFILEPATH, goobj_SCONST, goobj_SDYNIMPORT, goobj_SHOSTOBJ: + sym.Code = 'X' // should not see + } + if s.Version != 0 { + sym.Code += 'a' - 'A' + } + syms = append(syms, sym) + } + + for _, s := range pkg.Syms { + for _, r := range s.Reloc { + if !seen[r.Sym] { + seen[r.Sym] = true + sym := Sym{Name: goobjName(r.Sym), Code: 'U'} + if s.Version != 0 { + // should not happen but handle anyway + sym.Code = 'u' + } + syms = append(syms, sym) + } + } + } + + return syms +} diff --git a/src/cmd/nm/macho.go b/src/cmd/nm/macho.go new file mode 100644 index 000000000..c60bde55b --- /dev/null +++ b/src/cmd/nm/macho.go @@ -0,0 +1,69 @@ +// Copyright 2013 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. + +// Parsing of Mach-O executables (OS X). + +package main + +import ( + "debug/macho" + "os" + "sort" +) + +func machoSymbols(f *os.File) []Sym { + p, err := macho.NewFile(f) + if err != nil { + errorf("parsing %s: %v", f.Name(), err) + return nil + } + + if p.Symtab == nil { + errorf("%s: no symbol table", f.Name()) + return nil + } + + // Build sorted list of addresses of all symbols. + // We infer the size of a symbol by looking at where the next symbol begins. + var addrs []uint64 + for _, s := range p.Symtab.Syms { + addrs = append(addrs, s.Value) + } + sort.Sort(uint64s(addrs)) + + var syms []Sym + for _, s := range p.Symtab.Syms { + sym := Sym{Name: s.Name, Addr: s.Value, Code: '?'} + i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value }) + if i < len(addrs) { + sym.Size = int64(addrs[i] - s.Value) + } + if s.Sect == 0 { + sym.Code = 'U' + } else if int(s.Sect) <= len(p.Sections) { + sect := p.Sections[s.Sect-1] + switch sect.Seg { + case "__TEXT": + sym.Code = 'R' + case "__DATA": + sym.Code = 'D' + } + switch sect.Seg + " " + sect.Name { + case "__TEXT __text": + sym.Code = 'T' + case "__DATA __bss", "__DATA __noptrbss": + sym.Code = 'B' + } + } + syms = append(syms, sym) + } + + return syms +} + +type uint64s []uint64 + +func (x uint64s) Len() int { return len(x) } +func (x uint64s) Swap(i, j int) { x[i], x[j] = x[j], x[i] } +func (x uint64s) Less(i, j int) bool { return x[i] < x[j] } diff --git a/src/cmd/nm/nm.c b/src/cmd/nm/nm.c deleted file mode 100644 index 820942426..000000000 --- a/src/cmd/nm/nm.c +++ /dev/null @@ -1,401 +0,0 @@ -// Inferno utils/nm/nm.c -// http://code.google.com/p/inferno-os/source/browse/utils/nm/nm.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. - -/* - * nm.c -- drive nm - */ -#include -#include -#include -#include -#include - -enum{ - CHUNK = 256 /* must be power of 2 */ -}; - -char *errs; /* exit status */ -char *filename; /* current file */ -char symname[]="__.GOSYMDEF"; /* table of contents file name */ -int multifile; /* processing multiple files */ -int aflag; -int gflag; -int hflag; -int nflag; -int sflag; -int Sflag; -int uflag; -int Tflag; -int tflag; - -Sym **fnames; /* file path translation table */ -Sym **symptr; -int nsym; -Biobuf bout; - -int cmp(void*, void*); -void error(char*, ...); -void execsyms(int); -void psym(Sym*, void*); -void printsyms(Sym**, long); -void doar(Biobuf*); -void dofile(Biobuf*); -void zenter(Sym*); - -void -usage(void) -{ - fprint(2, "usage: nm [-aghnsSTu] file ...\n"); - exits("usage"); -} - -void -main(int argc, char *argv[]) -{ - int i; - Biobuf *bin; - - Binit(&bout, 1, OWRITE); - argv0 = argv[0]; - ARGBEGIN { - default: usage(); - case 'a': aflag = 1; break; - case 'g': gflag = 1; break; - case 'h': hflag = 1; break; - case 'n': nflag = 1; break; - case 's': sflag = 1; break; - case 'S': nflag = Sflag = 1; break; - case 'u': uflag = 1; break; - case 't': tflag = 1; break; - case 'T': Tflag = 1; break; - } ARGEND - if (argc == 0) - usage(); - if (argc > 1) - multifile++; - for(i=0; i 2 && strcmp(name+strlen(name)-2, ".o") == 0) - return; - error("inconsistent file %s in %s", - name, filename); - return; - } - if (!readar(bp, obj, offset+size, 1)) { - error("invalid symbol reference in file %s", - name); - return; - } - filename = name; - nsym=0; - objtraverse(psym, 0); - printsyms(symptr, nsym); - } -} - -/* - * process symbols in a file - */ -void -dofile(Biobuf *bp) -{ - int obj; - - obj = objtype(bp, 0); - if (obj < 0) - execsyms(Bfildes(bp)); - else - if (readobj(bp, obj)) { - nsym = 0; - objtraverse(psym, 0); - printsyms(symptr, nsym); - } -} - -/* - * comparison routine for sorting the symbol table - * this screws up on 'z' records when aflag == 1 - */ -int -cmp(void *vs, void *vt) -{ - Sym **s, **t; - - s = vs; - t = vt; - if(nflag) // sort on address (numeric) order - if((*s)->value < (*t)->value) - return -1; - else - return (*s)->value > (*t)->value; - if(sflag) // sort on file order (sequence) - return (*s)->sequence - (*t)->sequence; - return strcmp((*s)->name, (*t)->name); -} -/* - * enter a symbol in the table of filename elements - */ -void -zenter(Sym *s) -{ - static int maxf = 0; - - if (s->value > maxf) { - maxf = (s->value+CHUNK-1) &~ (CHUNK-1); - fnames = realloc(fnames, (maxf+1)*sizeof(*fnames)); - if(fnames == 0) { - error("out of memory", argv0); - exits("memory"); - } - } - fnames[s->value] = s; -} - -/* - * get the symbol table from an executable file, if it has one - */ -void -execsyms(int fd) -{ - Fhdr f; - Sym *s; - int32 n; - - seek(fd, 0, 0); - if (crackhdr(fd, &f) == 0) { - error("Can't read header for %s", filename); - return; - } - if (syminit(fd, &f) < 0) - return; - s = symbase(&n); - nsym = 0; - while(n--) - psym(s++, 0); - - printsyms(symptr, nsym); -} - -void -psym(Sym *s, void* p) -{ - USED(p); - switch(s->type) { - case 'T': - case 'L': - case 'D': - case 'B': - if (uflag) - return; - if (!aflag && ((s->name[0] == '.' || s->name[0] == '$'))) - return; - break; - case 'b': - case 'd': - case 'l': - case 't': - if (uflag || gflag) - return; - if (!aflag && ((s->name[0] == '.' || s->name[0] == '$'))) - return; - break; - case 'U': - if (gflag) - return; - break; - case 'Z': - if (!aflag) - return; - break; - case 'm': - if(!aflag || uflag || gflag) - return; - break; - case 'f': /* we only see a 'z' when the following is true*/ - if(!aflag || uflag || gflag) - return; - zenter(s); - break; - case 'a': - case 'p': - case 'z': - default: - if(!aflag || uflag || gflag) - return; - break; - } - symptr = realloc(symptr, (nsym+1)*sizeof(Sym*)); - if (symptr == 0) { - error("out of memory"); - exits("memory"); - } - symptr[nsym++] = s; -} - -const char *skipnames[] = { - "bss", - "data", - "ebss", - "edata", - "egcbss", - "egcdata", - "enoptrbss", - "enoptrdata", - "epclntab", - "erodata", - "esymtab", - "etext", - "etypelink", - "noptrbss", - "noptrdata", - "rodata", - "text", -}; - -int -skipsize(char *name) -{ - int i; - - for(i=0; ivalue && wid == 0) - wid = 8; - else if (s->value >= 0x100000000LL && wid == 8) - wid = 16; - } - for (i=0; itype == 'z') { - fileelem(fnames, (uchar *) s->name, path, 512); - cp = path; - } else - cp = s->name; - if (Tflag) - Bprint(&bout, "%8ux ", s->sig); - if (s->value || s->type == 'a' || s->type == 'p') - Bprint(&bout, "%*llux ", wid, s->value); - else - Bprint(&bout, "%*s ", wid, ""); - if(Sflag && !skipsize(cp)) { - vlong siz; - - siz = 0; - for(j=i+1; jname) && symptr[j]->type != 'a' && symptr[j]->type != 'p') { - siz = symptr[j]->value - s->value; - break; - } - } - if(siz > 0) - Bprint(&bout, "%*llud ", wid, siz); - } - Bprint(&bout, "%c %s", s->type, cp); - if(tflag && s->gotype) - Bprint(&bout, " %*llux", wid, s->gotype); - Bprint(&bout, "\n"); - } -} - -void -error(char *fmt, ...) -{ - Fmt f; - char buf[128]; - va_list arg; - - fmtfdinit(&f, 2, buf, sizeof buf); - fmtprint(&f, "%s: ", argv0); - va_start(arg, fmt); - fmtvprint(&f, fmt, arg); - va_end(arg); - fmtprint(&f, "\n"); - fmtfdflush(&f); - errs = "errors"; -} diff --git a/src/cmd/nm/nm.go b/src/cmd/nm/nm.go new file mode 100644 index 000000000..a4036184e --- /dev/null +++ b/src/cmd/nm/nm.go @@ -0,0 +1,184 @@ +// Copyright 2013 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 ( + "bufio" + "bytes" + "flag" + "fmt" + "io" + "log" + "os" + "sort" +) + +func usage() { + fmt.Fprintf(os.Stderr, "usage: go tool nm [-n] [-size] [-sort order] [-type] file...\n") + os.Exit(2) +} + +var ( + sortOrder = flag.String("sort", "name", "") + printSize = flag.Bool("size", false, "") + printType = flag.Bool("type", false, "") + + filePrefix = false +) + +func init() { + flag.Var(nflag(0), "n", "") // alias for -sort address +} + +type nflag int + +func (nflag) IsBoolFlag() bool { + return true +} + +func (nflag) Set(value string) error { + if value == "true" { + *sortOrder = "address" + } + return nil +} + +func (nflag) String() string { + if *sortOrder == "address" { + return "true" + } + return "false" +} + +func main() { + log.SetFlags(0) + flag.Usage = usage + flag.Parse() + + switch *sortOrder { + case "address", "name", "none", "size": + // ok + default: + fmt.Fprintf(os.Stderr, "nm: unknown sort order %q\n", *sortOrder) + os.Exit(2) + } + + args := flag.Args() + filePrefix = len(args) > 1 + if len(args) == 0 { + flag.Usage() + } + + for _, file := range args { + nm(file) + } + + os.Exit(exitCode) +} + +var exitCode = 0 + +func errorf(format string, args ...interface{}) { + log.Printf(format, args...) + exitCode = 1 +} + +type Sym struct { + Addr uint64 + Size int64 + Code rune + Name string + Type string +} + +var parsers = []struct { + prefix []byte + parse func(*os.File) []Sym +}{ + {[]byte("!\n"), goobjSymbols}, + {[]byte("go object "), goobjSymbols}, + {[]byte("\x7FELF"), elfSymbols}, + {[]byte("\xFE\xED\xFA\xCE"), machoSymbols}, + {[]byte("\xFE\xED\xFA\xCF"), machoSymbols}, + {[]byte("\xCE\xFA\xED\xFE"), machoSymbols}, + {[]byte("\xCF\xFA\xED\xFE"), machoSymbols}, + {[]byte("MZ"), peSymbols}, + {[]byte("\x00\x00\x01\xEB"), plan9Symbols}, // 386 + {[]byte("\x00\x00\x04\x07"), plan9Symbols}, // mips + {[]byte("\x00\x00\x06\x47"), plan9Symbols}, // arm + {[]byte("\x00\x00\x8A\x97"), plan9Symbols}, // amd64 +} + +func nm(file string) { + f, err := os.Open(file) + if err != nil { + errorf("%v", err) + return + } + defer f.Close() + + buf := make([]byte, 16) + io.ReadFull(f, buf) + f.Seek(0, 0) + + var syms []Sym + for _, p := range parsers { + if bytes.HasPrefix(buf, p.prefix) { + syms = p.parse(f) + goto HaveSyms + } + } + errorf("%v: unknown file format", file) + return + +HaveSyms: + switch *sortOrder { + case "address": + sort.Sort(byAddr(syms)) + case "name": + sort.Sort(byName(syms)) + case "size": + sort.Sort(bySize(syms)) + } + + w := bufio.NewWriter(os.Stdout) + for _, sym := range syms { + if filePrefix { + fmt.Fprintf(w, "%s:\t", file) + } + if sym.Code == 'U' { + fmt.Fprintf(w, "%8s", "") + } else { + fmt.Fprintf(w, "%8x", sym.Addr) + } + if *printSize { + fmt.Fprintf(w, " %10d", sym.Size) + } + fmt.Fprintf(w, " %c %s", sym.Code, sym.Name) + if *printType && sym.Type != "" { + fmt.Fprintf(w, " %s", sym.Type) + } + fmt.Fprintf(w, "\n") + } + w.Flush() +} + +type byAddr []Sym + +func (x byAddr) Len() int { return len(x) } +func (x byAddr) Swap(i, j int) { x[i], x[j] = x[j], x[i] } +func (x byAddr) Less(i, j int) bool { return x[i].Addr < x[j].Addr } + +type byName []Sym + +func (x byName) Len() int { return len(x) } +func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } +func (x byName) Less(i, j int) bool { return x[i].Name < x[j].Name } + +type bySize []Sym + +func (x bySize) Len() int { return len(x) } +func (x bySize) Swap(i, j int) { x[i], x[j] = x[j], x[i] } +func (x bySize) Less(i, j int) bool { return x[i].Size > x[j].Size } diff --git a/src/cmd/nm/nm_test.go b/src/cmd/nm/nm_test.go new file mode 100644 index 000000000..f4e47a42d --- /dev/null +++ b/src/cmd/nm/nm_test.go @@ -0,0 +1,99 @@ +// Copyright 2014 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 ( + "bufio" + "bytes" + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + "testing" +) + +var testData uint32 + +func checkSymbols(t *testing.T, nmoutput []byte) { + var checkSymbolsFound, testDataFound bool + scanner := bufio.NewScanner(bytes.NewBuffer(nmoutput)) + for scanner.Scan() { + f := strings.Fields(scanner.Text()) + if len(f) < 3 { + continue + } + switch f[2] { + case "cmd/nm.checkSymbols": + checkSymbolsFound = true + addr := "0x" + f[0] + if addr != fmt.Sprintf("%p", checkSymbols) { + t.Errorf("nm shows wrong address %v for checkSymbols (%p)", addr, checkSymbols) + } + case "cmd/nm.testData": + testDataFound = true + addr := "0x" + f[0] + if addr != fmt.Sprintf("%p", &testData) { + t.Errorf("nm shows wrong address %v for testData (%p)", addr, &testData) + } + } + } + if err := scanner.Err(); err != nil { + t.Errorf("error while reading symbols: %v", err) + return + } + if !checkSymbolsFound { + t.Error("nm shows no checkSymbols symbol") + } + if !testDataFound { + t.Error("nm shows no testData symbol") + } +} + +func TestNM(t *testing.T) { + if runtime.GOOS == "nacl" { + t.Skip("skipping on nacl") + } + + tmpDir, err := ioutil.TempDir("", "TestNM") + if err != nil { + t.Fatal("TempDir failed: ", err) + } + defer os.RemoveAll(tmpDir) + + testnmpath := filepath.Join(tmpDir, "testnm.exe") + out, err := exec.Command("go", "build", "-o", testnmpath, "cmd/nm").CombinedOutput() + if err != nil { + t.Fatalf("go build -o %v cmd/nm: %v\n%s", testnmpath, err, string(out)) + } + + testfiles := []string{ + "elf/testdata/gcc-386-freebsd-exec", + "elf/testdata/gcc-amd64-linux-exec", + "macho/testdata/gcc-386-darwin-exec", + "macho/testdata/gcc-amd64-darwin-exec", + "pe/testdata/gcc-amd64-mingw-exec", + "pe/testdata/gcc-386-mingw-exec", + "plan9obj/testdata/amd64-plan9-exec", + "plan9obj/testdata/386-plan9-exec", + } + for _, f := range testfiles { + exepath := filepath.Join(runtime.GOROOT(), "src", "pkg", "debug", f) + cmd := exec.Command(testnmpath, exepath) + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("go tool nm %v: %v\n%s", exepath, err, string(out)) + } + } + + cmd := exec.Command(testnmpath, os.Args[0]) + out, err = cmd.CombinedOutput() + if err != nil { + t.Fatalf("go tool nm %v: %v\n%s", os.Args[0], err, string(out)) + } + checkSymbols(t, out) +} diff --git a/src/cmd/nm/pe.go b/src/cmd/nm/pe.go new file mode 100644 index 000000000..52d05e51d --- /dev/null +++ b/src/cmd/nm/pe.go @@ -0,0 +1,98 @@ +// Copyright 2013 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. + +// Parsing of PE executables (Microsoft Windows). + +package main + +import ( + "debug/pe" + "os" + "sort" +) + +func peSymbols(f *os.File) []Sym { + p, err := pe.NewFile(f) + if err != nil { + errorf("parsing %s: %v", f.Name(), err) + return nil + } + + // Build sorted list of addresses of all symbols. + // We infer the size of a symbol by looking at where the next symbol begins. + var addrs []uint64 + + var imageBase uint64 + switch oh := p.OptionalHeader.(type) { + case *pe.OptionalHeader32: + imageBase = uint64(oh.ImageBase) + case *pe.OptionalHeader64: + imageBase = oh.ImageBase + default: + errorf("parsing %s: file format not recognized", f.Name()) + return nil + } + + var syms []Sym + for _, s := range p.Symbols { + const ( + N_UNDEF = 0 // An undefined (extern) symbol + N_ABS = -1 // An absolute symbol (e_value is a constant, not an address) + N_DEBUG = -2 // A debugging symbol + ) + sym := Sym{Name: s.Name, Addr: uint64(s.Value), Code: '?'} + switch s.SectionNumber { + case N_UNDEF: + sym.Code = 'U' + case N_ABS: + sym.Code = 'C' + case N_DEBUG: + sym.Code = '?' + default: + if s.SectionNumber < 0 { + errorf("parsing %s: invalid section number %d", f.Name(), s.SectionNumber) + return nil + } + if len(p.Sections) < int(s.SectionNumber) { + errorf("parsing %s: section number %d is large then max %d", f.Name(), s.SectionNumber, len(p.Sections)) + return nil + } + sect := p.Sections[s.SectionNumber-1] + const ( + text = 0x20 + data = 0x40 + bss = 0x80 + permX = 0x20000000 + permR = 0x40000000 + permW = 0x80000000 + ) + ch := sect.Characteristics + switch { + case ch&text != 0: + sym.Code = 'T' + case ch&data != 0: + if ch&permW == 0 { + sym.Code = 'R' + } else { + sym.Code = 'D' + } + case ch&bss != 0: + sym.Code = 'B' + } + sym.Addr += imageBase + uint64(sect.VirtualAddress) + } + syms = append(syms, sym) + addrs = append(addrs, sym.Addr) + } + + sort.Sort(uint64s(addrs)) + for i := range syms { + j := sort.Search(len(addrs), func(x int) bool { return addrs[x] > syms[i].Addr }) + if j < len(addrs) { + syms[i].Size = int64(addrs[j] - syms[i].Addr) + } + } + + return syms +} diff --git a/src/cmd/nm/plan9obj.go b/src/cmd/nm/plan9obj.go new file mode 100644 index 000000000..006c66ebf --- /dev/null +++ b/src/cmd/nm/plan9obj.go @@ -0,0 +1,48 @@ +// Copyright 2014 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. + +// Parsing of Plan 9 a.out executables. + +package main + +import ( + "debug/plan9obj" + "os" + "sort" +) + +func plan9Symbols(f *os.File) []Sym { + p, err := plan9obj.NewFile(f) + if err != nil { + errorf("parsing %s: %v", f.Name(), err) + return nil + } + + plan9Syms, err := p.Symbols() + if err != nil { + errorf("parsing %s: %v", f.Name(), err) + return nil + } + + // Build sorted list of addresses of all symbols. + // We infer the size of a symbol by looking at where the next symbol begins. + var addrs []uint64 + for _, s := range plan9Syms { + addrs = append(addrs, s.Value) + } + sort.Sort(uint64s(addrs)) + + var syms []Sym + + for _, s := range plan9Syms { + sym := Sym{Addr: s.Value, Name: s.Name, Code: rune(s.Type)} + i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value }) + if i < len(addrs) { + sym.Size = int64(addrs[i] - s.Value) + } + syms = append(syms, sym) + } + + return syms +} diff --git a/src/cmd/objdump/Makefile b/src/cmd/objdump/Makefile new file mode 100644 index 000000000..1b66c26ba --- /dev/null +++ b/src/cmd/objdump/Makefile @@ -0,0 +1,10 @@ +all: x86.go armasm.go + +x86.go: bundle + ./bundle -p main -x x86_ rsc.io/x86/x86asm | gofmt >x86.go + +armasm.go: bundle + ./bundle -p main -x arm_ rsc.io/arm/armasm | gofmt >armasm.go + +bundle: + go build -o bundle code.google.com/p/rsc/cmd/bundle diff --git a/src/cmd/objdump/armasm.go b/src/cmd/objdump/armasm.go new file mode 100644 index 000000000..764a3689e --- /dev/null +++ b/src/cmd/objdump/armasm.go @@ -0,0 +1,10821 @@ +// DO NOT EDIT. Generated by code.google.com/p/rsc/cmd/bundle +// bundle -p main -x arm_ rsc.io/arm/armasm + +/* decode.go */ + +// Copyright 2014 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 ( + "bytes" + "encoding/binary" + "fmt" + "io" + "strings" +) + +// An instFormat describes the format of an instruction encoding. +// An instruction with 32-bit value x matches the format if x&mask == value +// and the condition matches. +// The condition matches if x>>28 == 0xF && value>>28==0xF +// or if x>>28 != 0xF and value>>28 == 0. +// If x matches the format, then the rest of the fields describe how to interpret x. +// The opBits describe bits that should be extracted from x and added to the opcode. +// For example opBits = 0x1234 means that the value +// (2 bits at offset 1) followed by (4 bits at offset 3) +// should be added to op. +// Finally the args describe how to decode the instruction arguments. +// args is stored as a fixed-size array; if there are fewer than len(args) arguments, +// args[i] == 0 marks the end of the argument list. +type arm_instFormat struct { + mask uint32 + value uint32 + priority int8 + op arm_Op + opBits uint64 + args arm_instArgs +} + +type arm_instArgs [4]arm_instArg + +var ( + arm_errMode = fmt.Errorf("unsupported execution mode") + arm_errShort = fmt.Errorf("truncated instruction") + arm_errUnknown = fmt.Errorf("unknown instruction") +) + +var arm_decoderCover []bool + +// Decode decodes the leading bytes in src as a single instruction. +func arm_Decode(src []byte, mode arm_Mode) (inst arm_Inst, err error) { + if mode != arm_ModeARM { + return arm_Inst{}, arm_errMode + } + if len(src) < 4 { + return arm_Inst{}, arm_errShort + } + + if arm_decoderCover == nil { + arm_decoderCover = make([]bool, len(arm_instFormats)) + } + + x := binary.LittleEndian.Uint32(src) + + // The instFormat table contains both conditional and unconditional instructions. + // Considering only the top 4 bits, the conditional instructions use mask=0, value=0, + // while the unconditional instructions use mask=f, value=f. + // Prepare a version of x with the condition cleared to 0 in conditional instructions + // and then assume mask=f during matching. + const condMask = 0xf0000000 + xNoCond := x + if x&condMask != condMask { + xNoCond &^= condMask + } + var priority int8 +Search: + for i := range arm_instFormats { + f := &arm_instFormats[i] + if xNoCond&(f.mask|condMask) != f.value || f.priority <= priority { + continue + } + delta := uint32(0) + deltaShift := uint(0) + for opBits := f.opBits; opBits != 0; opBits >>= 16 { + n := uint(opBits & 0xFF) + off := uint((opBits >> 8) & 0xFF) + delta |= (x >> off) & (1<> 8) & (1<<4 - 1)) + case arm_arg_R_12: + return arm_Reg((x >> 12) & (1<<4 - 1)) + case arm_arg_R_16: + return arm_Reg((x >> 16) & (1<<4 - 1)) + + case arm_arg_R_12_nzcv: + r := arm_Reg((x >> 12) & (1<<4 - 1)) + if r == arm_R15 { + return arm_APSR_nzcv + } + return r + + case arm_arg_R_16_WB: + mode := arm_AddrLDM + if (x>>21)&1 != 0 { + mode = arm_AddrLDM_WB + } + return arm_Mem{Base: arm_Reg((x >> 16) & (1<<4 - 1)), Mode: mode} + + case arm_arg_R_rotate: + Rm := arm_Reg(x & (1<<4 - 1)) + typ, count := arm_decodeShift(x) + // ROR #0 here means ROR #0, but decodeShift rewrites to RRX #1. + if typ == arm_RotateRightExt { + return arm_Reg(Rm) + } + return arm_RegShift{Rm, typ, uint8(count)} + + case arm_arg_R_shift_R: + Rm := arm_Reg(x & (1<<4 - 1)) + Rs := arm_Reg((x >> 8) & (1<<4 - 1)) + typ := arm_Shift((x >> 5) & (1<<2 - 1)) + return arm_RegShiftReg{Rm, typ, Rs} + + case arm_arg_R_shift_imm: + Rm := arm_Reg(x & (1<<4 - 1)) + typ, count := arm_decodeShift(x) + if typ == arm_ShiftLeft && count == 0 { + return arm_Reg(Rm) + } + return arm_RegShift{Rm, typ, uint8(count)} + + case arm_arg_R1_0: + return arm_Reg((x & (1<<4 - 1))) + case arm_arg_R1_12: + return arm_Reg(((x >> 12) & (1<<4 - 1))) + case arm_arg_R2_0: + return arm_Reg((x & (1<<4 - 1)) | 1) + case arm_arg_R2_12: + return arm_Reg(((x >> 12) & (1<<4 - 1)) | 1) + + case arm_arg_SP: + return arm_SP + + case arm_arg_Sd_Dd: + v := (x >> 12) & (1<<4 - 1) + vx := (x >> 22) & 1 + sz := (x >> 8) & 1 + if sz != 0 { + return arm_D0 + arm_Reg(vx<<4+v) + } else { + return arm_S0 + arm_Reg(v<<1+vx) + } + + case arm_arg_Dd_Sd: + return arm_decodeArg(arm_arg_Sd_Dd, x^(1<<8)) + + case arm_arg_Sd: + v := (x >> 12) & (1<<4 - 1) + vx := (x >> 22) & 1 + return arm_S0 + arm_Reg(v<<1+vx) + + case arm_arg_Sm_Dm: + v := (x >> 0) & (1<<4 - 1) + vx := (x >> 5) & 1 + sz := (x >> 8) & 1 + if sz != 0 { + return arm_D0 + arm_Reg(vx<<4+v) + } else { + return arm_S0 + arm_Reg(v<<1+vx) + } + + case arm_arg_Sm: + v := (x >> 0) & (1<<4 - 1) + vx := (x >> 5) & 1 + return arm_S0 + arm_Reg(v<<1+vx) + + case arm_arg_Dn_half: + v := (x >> 16) & (1<<4 - 1) + vx := (x >> 7) & 1 + return arm_RegX{arm_D0 + arm_Reg(vx<<4+v), int((x >> 21) & 1)} + + case arm_arg_Sn_Dn: + v := (x >> 16) & (1<<4 - 1) + vx := (x >> 7) & 1 + sz := (x >> 8) & 1 + if sz != 0 { + return arm_D0 + arm_Reg(vx<<4+v) + } else { + return arm_S0 + arm_Reg(v<<1+vx) + } + + case arm_arg_Sn: + v := (x >> 16) & (1<<4 - 1) + vx := (x >> 7) & 1 + return arm_S0 + arm_Reg(v<<1+vx) + + case arm_arg_const: + v := x & (1<<8 - 1) + rot := (x >> 8) & (1<<4 - 1) * 2 + if rot > 0 && v&3 == 0 { + // could rotate less + return arm_ImmAlt{uint8(v), uint8(rot)} + } + if rot >= 24 && ((v<<(32-rot))&0xFF)>>(32-rot) == v { + // could wrap around to rot==0. + return arm_ImmAlt{uint8(v), uint8(rot)} + } + return arm_Imm(v>>rot | v<<(32-rot)) + + case arm_arg_endian: + return arm_Endian((x >> 9) & 1) + + case arm_arg_fbits: + return arm_Imm((16 << ((x >> 7) & 1)) - ((x&(1<<4-1))<<1 | (x>>5)&1)) + + case arm_arg_fp_0: + return arm_Imm(0) + + case arm_arg_imm24: + return arm_Imm(x & (1<<24 - 1)) + + case arm_arg_imm5: + return arm_Imm((x >> 7) & (1<<5 - 1)) + + case arm_arg_imm5_32: + x = (x >> 7) & (1<<5 - 1) + if x == 0 { + x = 32 + } + return arm_Imm(x) + + case arm_arg_imm5_nz: + x = (x >> 7) & (1<<5 - 1) + if x == 0 { + return nil + } + return arm_Imm(x) + + case arm_arg_imm_4at16_12at0: + return arm_Imm((x>>16)&(1<<4-1)<<12 | x&(1<<12-1)) + + case arm_arg_imm_12at8_4at0: + return arm_Imm((x>>8)&(1<<12-1)<<4 | x&(1<<4-1)) + + case arm_arg_imm_vfp: + x = (x>>16)&(1<<4-1)<<4 | x&(1<<4-1) + return arm_Imm(x) + + case arm_arg_label24: + imm := (x & (1<<24 - 1)) << 2 + return arm_PCRel(int32(imm<<6) >> 6) + + case arm_arg_label24H: + h := (x >> 24) & 1 + imm := (x&(1<<24-1))<<2 | h<<1 + return arm_PCRel(int32(imm<<6) >> 6) + + case arm_arg_label_m_12: + d := int32(x & (1<<12 - 1)) + return arm_Mem{Base: arm_PC, Mode: arm_AddrOffset, Offset: int16(-d)} + + case arm_arg_label_p_12: + d := int32(x & (1<<12 - 1)) + return arm_Mem{Base: arm_PC, Mode: arm_AddrOffset, Offset: int16(d)} + + case arm_arg_label_pm_12: + d := int32(x & (1<<12 - 1)) + u := (x >> 23) & 1 + if u == 0 { + d = -d + } + return arm_Mem{Base: arm_PC, Mode: arm_AddrOffset, Offset: int16(d)} + + case arm_arg_label_pm_4_4: + d := int32((x>>8)&(1<<4-1)<<4 | x&(1<<4-1)) + u := (x >> 23) & 1 + if u == 0 { + d = -d + } + return arm_PCRel(d) + + case arm_arg_lsb_width: + lsb := (x >> 7) & (1<<5 - 1) + msb := (x >> 16) & (1<<5 - 1) + if msb < lsb || msb >= 32 { + return nil + } + return arm_Imm(msb + 1 - lsb) + + case arm_arg_mem_R: + Rn := arm_Reg((x >> 16) & (1<<4 - 1)) + return arm_Mem{Base: Rn, Mode: arm_AddrOffset} + + case arm_arg_mem_R_pm_R_postindex: + // Treat [],+/- like [,+/-{,}]{!} + // by forcing shift bits to <<0 and P=0, W=0 (postindex=true). + return arm_decodeArg(arm_arg_mem_R_pm_R_shift_imm_W, x&^((1<<7-1)<<5|1<<24|1<<21)) + + case arm_arg_mem_R_pm_R_W: + // Treat [,+/-]{!} like [,+/-{,}]{!} + // by forcing shift bits to <<0. + return arm_decodeArg(arm_arg_mem_R_pm_R_shift_imm_W, x&^((1<<7-1)<<5)) + + case arm_arg_mem_R_pm_R_shift_imm_offset: + // Treat [],+/-{,} like [,+/-{,}]{!} + // by forcing P=1, W=0 (index=false, wback=false). + return arm_decodeArg(arm_arg_mem_R_pm_R_shift_imm_W, x&^(1<<21)|1<<24) + + case arm_arg_mem_R_pm_R_shift_imm_postindex: + // Treat [],+/-{,} like [,+/-{,}]{!} + // by forcing P=0, W=0 (postindex=true). + return arm_decodeArg(arm_arg_mem_R_pm_R_shift_imm_W, x&^(1<<24|1<<21)) + + case arm_arg_mem_R_pm_R_shift_imm_W: + Rn := arm_Reg((x >> 16) & (1<<4 - 1)) + Rm := arm_Reg(x & (1<<4 - 1)) + typ, count := arm_decodeShift(x) + u := (x >> 23) & 1 + w := (x >> 21) & 1 + p := (x >> 24) & 1 + if p == 0 && w == 1 { + return nil + } + sign := int8(+1) + if u == 0 { + sign = -1 + } + mode := arm_AddrMode(uint8(p<<1) | uint8(w^1)) + return arm_Mem{Base: Rn, Mode: mode, Sign: sign, Index: Rm, Shift: typ, Count: count} + + case arm_arg_mem_R_pm_imm12_offset: + // Treat [,#+/-] like [{,#+/-}]{!} + // by forcing P=1, W=0 (index=false, wback=false). + return arm_decodeArg(arm_arg_mem_R_pm_imm12_W, x&^(1<<21)|1<<24) + + case arm_arg_mem_R_pm_imm12_postindex: + // Treat [],#+/- like [{,#+/-}]{!} + // by forcing P=0, W=0 (postindex=true). + return arm_decodeArg(arm_arg_mem_R_pm_imm12_W, x&^(1<<24|1<<21)) + + case arm_arg_mem_R_pm_imm12_W: + Rn := arm_Reg((x >> 16) & (1<<4 - 1)) + u := (x >> 23) & 1 + w := (x >> 21) & 1 + p := (x >> 24) & 1 + if p == 0 && w == 1 { + return nil + } + sign := int8(+1) + if u == 0 { + sign = -1 + } + imm := int16(x & (1<<12 - 1)) + mode := arm_AddrMode(uint8(p<<1) | uint8(w^1)) + return arm_Mem{Base: Rn, Mode: mode, Offset: int16(sign) * imm} + + case arm_arg_mem_R_pm_imm8_postindex: + // Treat [],#+/- like [{,#+/-}]{!} + // by forcing P=0, W=0 (postindex=true). + return arm_decodeArg(arm_arg_mem_R_pm_imm8_W, x&^(1<<24|1<<21)) + + case arm_arg_mem_R_pm_imm8_W: + Rn := arm_Reg((x >> 16) & (1<<4 - 1)) + u := (x >> 23) & 1 + w := (x >> 21) & 1 + p := (x >> 24) & 1 + if p == 0 && w == 1 { + return nil + } + sign := int8(+1) + if u == 0 { + sign = -1 + } + imm := int16((x>>8)&(1<<4-1)<<4 | x&(1<<4-1)) + mode := arm_AddrMode(uint8(p<<1) | uint8(w^1)) + return arm_Mem{Base: Rn, Mode: mode, Offset: int16(sign) * imm} + + case arm_arg_mem_R_pm_imm8at0_offset: + Rn := arm_Reg((x >> 16) & (1<<4 - 1)) + u := (x >> 23) & 1 + sign := int8(+1) + if u == 0 { + sign = -1 + } + imm := int16(x&(1<<8-1)) << 2 + return arm_Mem{Base: Rn, Mode: arm_AddrOffset, Offset: int16(sign) * imm} + + case arm_arg_option: + return arm_Imm(x & (1<<4 - 1)) + + case arm_arg_registers: + return arm_RegList(x & (1<<16 - 1)) + + case arm_arg_registers2: + x &= 1<<16 - 1 + n := 0 + for i := 0; i < 16; i++ { + if x>>uint(i)&1 != 0 { + n++ + } + } + if n < 2 { + return nil + } + return arm_RegList(x) + + case arm_arg_registers1: + Rt := (x >> 12) & (1<<4 - 1) + return arm_RegList(1 << Rt) + + case arm_arg_satimm4: + return arm_Imm((x >> 16) & (1<<4 - 1)) + + case arm_arg_satimm5: + return arm_Imm((x >> 16) & (1<<5 - 1)) + + case arm_arg_satimm4m1: + return arm_Imm((x>>16)&(1<<4-1) + 1) + + case arm_arg_satimm5m1: + return arm_Imm((x>>16)&(1<<5-1) + 1) + + case arm_arg_widthm1: + return arm_Imm((x>>16)&(1<<5-1) + 1) + + } +} + +// decodeShift decodes the shift-by-immediate encoded in x. +func arm_decodeShift(x uint32) (arm_Shift, uint8) { + count := (x >> 7) & (1<<5 - 1) + typ := arm_Shift((x >> 5) & (1<<2 - 1)) + switch typ { + case arm_ShiftRight, arm_ShiftRightSigned: + if count == 0 { + count = 32 + } + case arm_RotateRight: + if count == 0 { + typ = arm_RotateRightExt + count = 1 + } + } + return typ, uint8(count) +} + +/* gnu.go */ + +// Copyright 2014 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. + +var arm_saveDot = strings.NewReplacer( + ".F16", "_dot_F16", + ".F32", "_dot_F32", + ".F64", "_dot_F64", + ".S32", "_dot_S32", + ".U32", "_dot_U32", + ".FXS", "_dot_S", + ".FXU", "_dot_U", + ".32", "_dot_32", +) + +// GNUSyntax returns the GNU assembler syntax for the instruction, as defined by GNU binutils. +// This form typically matches the syntax defined in the ARM Reference Manual. +func arm_GNUSyntax(inst arm_Inst) string { + var buf bytes.Buffer + op := inst.Op.String() + op = arm_saveDot.Replace(op) + op = strings.Replace(op, ".", "", -1) + op = strings.Replace(op, "_dot_", ".", -1) + op = strings.ToLower(op) + buf.WriteString(op) + sep := " " + for i, arg := range inst.Args { + if arg == nil { + break + } + text := arm_gnuArg(&inst, i, arg) + if text == "" { + continue + } + buf.WriteString(sep) + sep = ", " + buf.WriteString(text) + } + return buf.String() +} + +func arm_gnuArg(inst *arm_Inst, argIndex int, arg arm_Arg) string { + switch inst.Op &^ 15 { + case arm_LDRD_EQ, arm_LDREXD_EQ, arm_STRD_EQ: + if argIndex == 1 { + // second argument in consecutive pair not printed + return "" + } + case arm_STREXD_EQ: + if argIndex == 2 { + // second argument in consecutive pair not printed + return "" + } + } + + switch arg := arg.(type) { + case arm_Imm: + switch inst.Op &^ 15 { + case arm_BKPT_EQ: + return fmt.Sprintf("%#04x", uint32(arg)) + case arm_SVC_EQ: + return fmt.Sprintf("%#08x", uint32(arg)) + } + return fmt.Sprintf("#%d", int32(arg)) + + case arm_ImmAlt: + return fmt.Sprintf("#%d, %d", arg.Val, arg.Rot) + + case arm_Mem: + R := arm_gnuArg(inst, -1, arg.Base) + X := "" + if arg.Sign != 0 { + X = "" + if arg.Sign < 0 { + X = "-" + } + X += arm_gnuArg(inst, -1, arg.Index) + if arg.Shift == arm_ShiftLeft && arg.Count == 0 { + // nothing + } else if arg.Shift == arm_RotateRightExt { + X += ", rrx" + } else { + X += fmt.Sprintf(", %s #%d", strings.ToLower(arg.Shift.String()), arg.Count) + } + } else { + X = fmt.Sprintf("#%d", arg.Offset) + } + + switch arg.Mode { + case arm_AddrOffset: + if X == "#0" { + return fmt.Sprintf("[%s]", R) + } + return fmt.Sprintf("[%s, %s]", R, X) + case arm_AddrPreIndex: + return fmt.Sprintf("[%s, %s]!", R, X) + case arm_AddrPostIndex: + return fmt.Sprintf("[%s], %s", R, X) + case arm_AddrLDM: + if X == "#0" { + return R + } + case arm_AddrLDM_WB: + if X == "#0" { + return R + "!" + } + } + return fmt.Sprintf("[%s Mode(%d) %s]", R, int(arg.Mode), X) + + case arm_PCRel: + return fmt.Sprintf(".%+#x", int32(arg)+4) + + case arm_Reg: + switch inst.Op &^ 15 { + case arm_LDREX_EQ: + if argIndex == 0 { + return fmt.Sprintf("r%d", int32(arg)) + } + } + switch arg { + case arm_R10: + return "sl" + case arm_R11: + return "fp" + case arm_R12: + return "ip" + } + + case arm_RegList: + var buf bytes.Buffer + fmt.Fprintf(&buf, "{") + sep := "" + for i := 0; i < 16; i++ { + if arg&(1<= arm_Op(len(arm_opstr)) || arm_opstr[op] == "" { + return fmt.Sprintf("Op(%d)", int(op)) + } + return arm_opstr[op] +} + +// An Inst is a single instruction. +type arm_Inst struct { + Op arm_Op // Opcode mnemonic + Enc uint32 // Raw encoding bits. + Len int // Length of encoding in bytes. + Args arm_Args // Instruction arguments, in ARM manual order. +} + +func (i arm_Inst) String() string { + var buf bytes.Buffer + buf.WriteString(i.Op.String()) + for j, arg := range i.Args { + if arg == nil { + break + } + if j == 0 { + buf.WriteString(" ") + } else { + buf.WriteString(", ") + } + buf.WriteString(arg.String()) + } + return buf.String() +} + +// An Args holds the instruction arguments. +// If an instruction has fewer than 4 arguments, +// the final elements in the array are nil. +type arm_Args [4]arm_Arg + +// An Arg is a single instruction argument, one of these types: +// Endian, Imm, Mem, PCRel, Reg, RegList, RegShift, RegShiftReg. +type arm_Arg interface { + IsArg() + String() string +} + +type arm_Float32Imm float32 + +func (arm_Float32Imm) IsArg() {} + +func (f arm_Float32Imm) String() string { + return fmt.Sprintf("#%v", float32(f)) +} + +type arm_Float64Imm float32 + +func (arm_Float64Imm) IsArg() {} + +func (f arm_Float64Imm) String() string { + return fmt.Sprintf("#%v", float64(f)) +} + +// An Imm is an integer constant. +type arm_Imm uint32 + +func (arm_Imm) IsArg() {} + +func (i arm_Imm) String() string { + return fmt.Sprintf("#%#x", uint32(i)) +} + +// A ImmAlt is an alternate encoding of an integer constant. +type arm_ImmAlt struct { + Val uint8 + Rot uint8 +} + +func (arm_ImmAlt) IsArg() {} + +func (i arm_ImmAlt) Imm() arm_Imm { + v := uint32(i.Val) + r := uint(i.Rot) + return arm_Imm(v>>r | v<<(32-r)) +} + +func (i arm_ImmAlt) String() string { + return fmt.Sprintf("#%#x, %d", i.Val, i.Rot) +} + +// A Label is a text (code) address. +type arm_Label uint32 + +func (arm_Label) IsArg() {} + +func (i arm_Label) String() string { + return fmt.Sprintf("%#x", uint32(i)) +} + +// A Reg is a single register. +// The zero value denotes R0, not the absence of a register. +type arm_Reg uint8 + +const ( + arm_R0 arm_Reg = iota + arm_R1 + arm_R2 + arm_R3 + arm_R4 + arm_R5 + arm_R6 + arm_R7 + arm_R8 + arm_R9 + arm_R10 + arm_R11 + arm_R12 + arm_R13 + arm_R14 + arm_R15 + + arm_S0 + arm_S1 + arm_S2 + arm_S3 + arm_S4 + arm_S5 + arm_S6 + arm_S7 + arm_S8 + arm_S9 + arm_S10 + arm_S11 + arm_S12 + arm_S13 + arm_S14 + arm_S15 + arm_S16 + arm_S17 + arm_S18 + arm_S19 + arm_S20 + arm_S21 + arm_S22 + arm_S23 + arm_S24 + arm_S25 + arm_S26 + arm_S27 + arm_S28 + arm_S29 + arm_S30 + arm_S31 + + arm_D0 + arm_D1 + arm_D2 + arm_D3 + arm_D4 + arm_D5 + arm_D6 + arm_D7 + arm_D8 + arm_D9 + arm_D10 + arm_D11 + arm_D12 + arm_D13 + arm_D14 + arm_D15 + arm_D16 + arm_D17 + arm_D18 + arm_D19 + arm_D20 + arm_D21 + arm_D22 + arm_D23 + arm_D24 + arm_D25 + arm_D26 + arm_D27 + arm_D28 + arm_D29 + arm_D30 + arm_D31 + + arm_APSR + arm_APSR_nzcv + arm_FPSCR + + arm_SP = arm_R13 + arm_LR = arm_R14 + arm_PC = arm_R15 +) + +func (arm_Reg) IsArg() {} + +func (r arm_Reg) String() string { + switch r { + case arm_APSR: + return "APSR" + case arm_APSR_nzcv: + return "APSR_nzcv" + case arm_FPSCR: + return "FPSCR" + case arm_SP: + return "SP" + case arm_PC: + return "PC" + case arm_LR: + return "LR" + } + if arm_R0 <= r && r <= arm_R15 { + return fmt.Sprintf("R%d", int(r-arm_R0)) + } + if arm_S0 <= r && r <= arm_S31 { + return fmt.Sprintf("S%d", int(r-arm_S0)) + } + if arm_D0 <= r && r <= arm_D31 { + return fmt.Sprintf("D%d", int(r-arm_D0)) + } + return fmt.Sprintf("Reg(%d)", int(r)) +} + +// A RegX represents a fraction of a multi-value register. +// The Index field specifies the index number, +// but the size of the fraction is not specified. +// It must be inferred from the instruction and the register type. +// For example, in a VMOV instruction, RegX{D5, 1} represents +// the top 32 bits of the 64-bit D5 register. +type arm_RegX struct { + Reg arm_Reg + Index int +} + +func (arm_RegX) IsArg() {} + +func (r arm_RegX) String() string { + return fmt.Sprintf("%s[%d]", r.Reg, r.Index) +} + +// A RegList is a register list. +// Bits at indexes x = 0 through 15 indicate whether the corresponding Rx register is in the list. +type arm_RegList uint16 + +func (arm_RegList) IsArg() {} + +func (r arm_RegList) String() string { + var buf bytes.Buffer + fmt.Fprintf(&buf, "{") + sep := "" + for i := 0; i < 16; i++ { + if r&(1< is a lie; the assembler uses @> 0 +// instead of @x> 1, but i wanted to be clear that it +// was a different operation (rotate right extended, not rotate right). +var arm_plan9Shift = []string{"<<", ">>", "->", "@>", "@x>"} + +func arm_plan9Arg(inst *arm_Inst, pc uint64, symname func(uint64) (string, uint64), arg arm_Arg) string { + switch a := arg.(type) { + case arm_Endian: + + case arm_Imm: + return fmt.Sprintf("$%d", int(a)) + + case arm_Mem: + + case arm_PCRel: + addr := uint32(pc) + 8 + uint32(a) + if s, base := symname(uint64(addr)); s != "" && uint64(addr) == base { + return fmt.Sprintf("%s(SB)", s) + } + return fmt.Sprintf("%#x", addr) + + case arm_Reg: + if a < 16 { + return fmt.Sprintf("R%d", int(a)) + } + + case arm_RegList: + var buf bytes.Buffer + start := -2 + end := -2 + fmt.Fprintf(&buf, "[") + flush := func() { + if start >= 0 { + if buf.Len() > 1 { + fmt.Fprintf(&buf, ",") + } + if start == end { + fmt.Fprintf(&buf, "R%d", start) + } else { + fmt.Fprintf(&buf, "R%d-R%d", start, end) + } + } + } + for i := 0; i < 16; i++ { + if a&(1< ,,# cond:4|0|0|1|0|1|0|1|S|Rn:4|Rd:4|imm12:12 + {0x0fe00090, 0x00a00010, 4, arm_ADC_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_R}}, // ADC{S} ,,, cond:4|0|0|0|0|1|0|1|S|Rn:4|Rd:4|Rs:4|0|type:2|1|Rm:4 + {0x0fe00010, 0x00a00000, 2, arm_ADC_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_imm}}, // ADC{S} ,,{,} cond:4|0|0|0|0|1|0|1|S|Rn:4|Rd:4|imm5:5|type:2|0|Rm:4 + {0x0fe00000, 0x02800000, 2, arm_ADD_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_const}}, // ADD{S} ,,# cond:4|0|0|1|0|1|0|0|S|Rn:4|Rd:4|imm12:12 + {0x0fe00090, 0x00800010, 4, arm_ADD_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_R}}, // ADD{S} ,,, cond:4|0|0|0|0|1|0|0|S|Rn:4|Rd:4|Rs:4|0|type:2|1|Rm:4 + {0x0fe00010, 0x00800000, 2, arm_ADD_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_imm}}, // ADD{S} ,,{,} cond:4|0|0|0|0|1|0|0|S|Rn:4|Rd:4|imm5:5|type:2|0|Rm:4 + {0x0fef0000, 0x028d0000, 2, arm_ADD_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_SP, arm_arg_const}}, // ADD{S} ,SP,# cond:4|0|0|1|0|1|0|0|S|1|1|0|1|Rd:4|imm12:12 + {0x0fef0010, 0x008d0000, 2, arm_ADD_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_SP, arm_arg_R_shift_imm}}, // ADD{S} ,SP,{,} cond:4|0|0|0|0|1|0|0|S|1|1|0|1|Rd:4|imm5:5|type:2|0|Rm:4 + {0x0fe00000, 0x02000000, 2, arm_AND_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_const}}, // AND{S} ,,# cond:4|0|0|1|0|0|0|0|S|Rn:4|Rd:4|imm12:12 + {0x0fe00090, 0x00000010, 4, arm_AND_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_R}}, // AND{S} ,,, cond:4|0|0|0|0|0|0|0|S|Rn:4|Rd:4|Rs:4|0|type:2|1|Rm:4 + {0x0fe00010, 0x00000000, 2, arm_AND_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_imm}}, // AND{S} ,,{,} cond:4|0|0|0|0|0|0|0|S|Rn:4|Rd:4|imm5:5|type:2|0|Rm:4 + {0x0fef0070, 0x01a00040, 4, arm_ASR_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_imm5_32}}, // ASR{S} ,,# cond:4|0|0|0|1|1|0|1|S|0|0|0|0|Rd:4|imm5:5|1|0|0|Rm:4 + {0x0fef00f0, 0x01a00050, 4, arm_ASR_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_R_8}}, // ASR{S} ,, cond:4|0|0|0|1|1|0|1|S|0|0|0|0|Rd:4|Rm:4|0|1|0|1|Rn:4 + {0x0f000000, 0x0a000000, 4, arm_B_EQ, 0x1c04, arm_instArgs{arm_arg_label24}}, // B cond:4|1|0|1|0|imm24:24 + {0x0fe0007f, 0x07c0001f, 4, arm_BFC_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_imm5, arm_arg_lsb_width}}, // BFC ,#,# cond:4|0|1|1|1|1|1|0|msb:5|Rd:4|lsb:5|0|0|1|1|1|1|1 + {0x0fe00070, 0x07c00010, 2, arm_BFI_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_imm5, arm_arg_lsb_width}}, // BFI ,,#,# cond:4|0|1|1|1|1|1|0|msb:5|Rd:4|lsb:5|0|0|1|Rn:4 + {0x0fe00000, 0x03c00000, 2, arm_BIC_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_const}}, // BIC{S} ,,# cond:4|0|0|1|1|1|1|0|S|Rn:4|Rd:4|imm12:12 + {0x0fe00090, 0x01c00010, 4, arm_BIC_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_R}}, // BIC{S} ,,, cond:4|0|0|0|1|1|1|0|S|Rn:4|Rd:4|Rs:4|0|type:2|1|Rm:4 + {0x0fe00010, 0x01c00000, 2, arm_BIC_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_imm}}, // BIC{S} ,,{,} cond:4|0|0|0|1|1|1|0|S|Rn:4|Rd:4|imm5:5|type:2|0|Rm:4 + {0x0ff000f0, 0x01200070, 4, arm_BKPT_EQ, 0x1c04, arm_instArgs{arm_arg_imm_12at8_4at0}}, // BKPT # cond:4|0|0|0|1|0|0|1|0|imm12:12|0|1|1|1|imm4:4 + {0x0f000000, 0x0b000000, 4, arm_BL_EQ, 0x1c04, arm_instArgs{arm_arg_label24}}, // BL cond:4|1|0|1|1|imm24:24 + {0xfe000000, 0xfa000000, 4, arm_BLX, 0x0, arm_instArgs{arm_arg_label24H}}, // BLX 1|1|1|1|1|0|1|H|imm24:24 + {0x0ffffff0, 0x012fff30, 4, arm_BLX_EQ, 0x1c04, arm_instArgs{arm_arg_R_0}}, // BLX cond:4|0|0|0|1|0|0|1|0|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4 + {0x0ff000f0, 0x012fff30, 3, arm_BLX_EQ, 0x1c04, arm_instArgs{arm_arg_R_0}}, // BLX cond:4|0|0|0|1|0|0|1|0|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4 + {0x0ffffff0, 0x012fff10, 4, arm_BX_EQ, 0x1c04, arm_instArgs{arm_arg_R_0}}, // BX cond:4|0|0|0|1|0|0|1|0|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4 + {0x0ff000f0, 0x012fff10, 3, arm_BX_EQ, 0x1c04, arm_instArgs{arm_arg_R_0}}, // BX cond:4|0|0|0|1|0|0|1|0|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4 + {0x0ffffff0, 0x012fff20, 4, arm_BXJ_EQ, 0x1c04, arm_instArgs{arm_arg_R_0}}, // BXJ cond:4|0|0|0|1|0|0|1|0|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|0|0|1|0|Rm:4 + {0x0ff000f0, 0x012fff20, 3, arm_BXJ_EQ, 0x1c04, arm_instArgs{arm_arg_R_0}}, // BXJ cond:4|0|0|0|1|0|0|1|0|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|0|0|1|0|Rm:4 + {0xffffffff, 0xf57ff01f, 4, arm_CLREX, 0x0, arm_instArgs{}}, // CLREX 1|1|1|1|0|1|0|1|0|1|1|1|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|0|0|1|(1)|(1)|(1)|(1) + {0xfff000f0, 0xf57ff01f, 3, arm_CLREX, 0x0, arm_instArgs{}}, // CLREX 1|1|1|1|0|1|0|1|0|1|1|1|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|0|0|1|(1)|(1)|(1)|(1) + {0x0fff0ff0, 0x016f0f10, 4, arm_CLZ_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0}}, // CLZ , cond:4|0|0|0|1|0|1|1|0|(1)|(1)|(1)|(1)|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4 + {0x0ff000f0, 0x016f0f10, 3, arm_CLZ_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0}}, // CLZ , cond:4|0|0|0|1|0|1|1|0|(1)|(1)|(1)|(1)|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4 + {0x0ff0f000, 0x03700000, 4, arm_CMN_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_const}}, // CMN ,# cond:4|0|0|1|1|0|1|1|1|Rn:4|(0)|(0)|(0)|(0)|imm12:12 + {0x0ff00000, 0x03700000, 3, arm_CMN_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_const}}, // CMN ,# cond:4|0|0|1|1|0|1|1|1|Rn:4|(0)|(0)|(0)|(0)|imm12:12 + {0x0ff0f090, 0x01700010, 4, arm_CMN_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_shift_R}}, // CMN ,, cond:4|0|0|0|1|0|1|1|1|Rn:4|(0)|(0)|(0)|(0)|Rs:4|0|type:2|1|Rm:4 + {0x0ff00090, 0x01700010, 3, arm_CMN_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_shift_R}}, // CMN ,, cond:4|0|0|0|1|0|1|1|1|Rn:4|(0)|(0)|(0)|(0)|Rs:4|0|type:2|1|Rm:4 + {0x0ff0f010, 0x01700000, 4, arm_CMN_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_shift_imm}}, // CMN ,{,} cond:4|0|0|0|1|0|1|1|1|Rn:4|(0)|(0)|(0)|(0)|imm5:5|type:2|0|Rm:4 + {0x0ff00010, 0x01700000, 3, arm_CMN_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_shift_imm}}, // CMN ,{,} cond:4|0|0|0|1|0|1|1|1|Rn:4|(0)|(0)|(0)|(0)|imm5:5|type:2|0|Rm:4 + {0x0ff0f000, 0x03500000, 4, arm_CMP_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_const}}, // CMP ,# cond:4|0|0|1|1|0|1|0|1|Rn:4|(0)|(0)|(0)|(0)|imm12:12 + {0x0ff00000, 0x03500000, 3, arm_CMP_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_const}}, // CMP ,# cond:4|0|0|1|1|0|1|0|1|Rn:4|(0)|(0)|(0)|(0)|imm12:12 + {0x0ff0f090, 0x01500010, 4, arm_CMP_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_shift_R}}, // CMP ,, cond:4|0|0|0|1|0|1|0|1|Rn:4|(0)|(0)|(0)|(0)|Rs:4|0|type:2|1|Rm:4 + {0x0ff00090, 0x01500010, 3, arm_CMP_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_shift_R}}, // CMP ,, cond:4|0|0|0|1|0|1|0|1|Rn:4|(0)|(0)|(0)|(0)|Rs:4|0|type:2|1|Rm:4 + {0x0ff0f010, 0x01500000, 4, arm_CMP_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_shift_imm}}, // CMP ,{,} cond:4|0|0|0|1|0|1|0|1|Rn:4|(0)|(0)|(0)|(0)|imm5:5|type:2|0|Rm:4 + {0x0ff00010, 0x01500000, 3, arm_CMP_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_shift_imm}}, // CMP ,{,} cond:4|0|0|0|1|0|1|0|1|Rn:4|(0)|(0)|(0)|(0)|imm5:5|type:2|0|Rm:4 + {0x0ffffff0, 0x0320f0f0, 4, arm_DBG_EQ, 0x1c04, arm_instArgs{arm_arg_option}}, // DBG #